目錄結構
2.1.第一步:在【settings.py】裏新增郵箱配置信息
2.2.第二步:在【helloworld/hello/views.py】裏新增視圖函數
2.3.第三步:在【helloworld/helloworld/urls.py】裏新增url匹配規則
2.5.第五步:任一瀏覽器上輸入url地址【http://192.168.1.81:8000/send_email_004/】進行訪問後,查看結果
3.1.類EmailMultiAlternatives裏的方法【__init__】的源碼簡單分析
3.2.類EmailMultiAlternatives裏的方法【attach_file】的源碼簡單分析
3.3.類EmailMultiAlternatives裏的方法【attach】的源碼簡單分析
1.寫這篇博客的目的
主要記錄如何通過django來實現這個功能:發送滿足【郵件正文值爲一個html頁面+有多個附件】的單個郵件;
發送滿足【郵件正文值爲一個html頁面+有多個附件】的單個郵件,可以使用類EmailMultiAlternative;
類EmailMultiAlternative提供了三個方法:attach_file()、attach_alternative()、send(),這三個方法的主要作用分別是:
- attach_file()的主要作用:把指定的一個文件當做郵件附件;
- attach_alternative()的主要作用:使郵件正文爲一個指定的html頁面;
- send()的主要作用:執行發送郵件的動作;
完整操作流程可以看接下來的內容;
2.完整操作流程
2.1.第一步:在【settings.py】裏新增郵箱配置信息
# 下面的代碼都是我個人新增的,不是djano框架默認生成的; # 1.1.配置qq郵箱信息 EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' # 值必須爲這個 EMAIL_USE_SSL = True # SSL加密方式,值必須爲True EMAIL_HOST = 'smtp.qq.com' # 發送郵件的qq郵箱的SMTP服務器 EMAIL_PORT = 465 # QQ郵箱對應的SMTP服務器端口 EMAIL_HOST_USER = '[email protected]' # 發件人 EMAIL_HOST_PASSWORD = 'dwvvnvjerwcvswp' # qq授權碼(不能使用qq密碼只能使用qq授權碼) EMAIL_FROM = '洪景盛<[email protected]>' # 郵件顯示的發件人
2.2.第二步:在【helloworld/hello/views.py】裏新增視圖函數
def send_email_004(request): '''發送【郵件正文值爲一個html頁面+有多個郵件附件】的單個郵件''' email = EmailMultiAlternatives( subject = "這是郵件的郵件標題(發送【郵件正文值爲一個html頁面+有多個郵件附件】的單個郵件)", body = "這是郵件的正文", from_email = "[email protected]", # 發件人 to = ["[email protected]","[email protected]"],# 收件人郵箱可以是任意的不限個數的郵箱 ) root_route= os.path.dirname(os.path.realpath(__file__)) # 應用【hello】的根目錄 # print(root_route) # 郵件附件裏的第一個附件爲:一個html頁面【這是html頁面噢.html】 route_1 = os.path.join(root_route,"public","html","test","這是html頁面噢.html") email.attach_file(path=route_1) # 郵件附件裏的第二個附件爲:一個pdf【202101持續測試白皮書v1.0-Lite.pdf】 route_2 = os.path.join(root_route,"public","pdf","test","202101持續測試白皮書v1.0-Lite.pdf") email.attach_file(path=route_2) # 郵件附件裏的第三個附件爲:一個圖片【1.jpg】 route_3 = os.path.join(root_route,"public","picture","test","1.jpg") email.attach_file(path=route_3) # 郵件附件裏的第四個附件爲:一個txt【這是txt文檔哦.txt】 route_4 = os.path.join(root_route,"public","txt","test","這是txt文檔哦.txt") email.attach_file(path=route_4) # 郵件附件裏的第五個附件爲:一個視頻【從21樓拍的海邊風景視頻.mp4】 route_5 = os.path.join(root_route,"public","video","test","從21樓拍的海邊風景視頻.mp4") email.attach_file(path=route_5) # 郵件附件裏的第六個附件爲:一個word【這是word文檔噢.docx】 route_6 = os.path.join(root_route,"public","word","test","這是word文檔噢.docx") email.attach_file(path=route_6) # 郵件附件裏的第七個附件爲:一個圖片【2.jpg】 # route_7 = os.path.join(root_route,"public","picture","test","2.jpg") # img_data = open(route_7,"rb") # email.attach(filename="2.jpg",content=img_data.read(),mimetype="image/jpg") # attach方法使用起來比較複雜,attach_file方法使用起來很方便,所以後續都只使用attach_file方法; html_content = ''' <!DOCTYPE HTML> <html> <head> <meta charset="UTF-8"> <title>帶圖片的郵件</title> </head> <body> 這是第一張圖片,點擊圖片後可跳轉到我的博客首頁<br> <a href="https://www.cnblogs.com/xiamen-momo/" target="_blank"> <p> <img src="http://www.w3school.com.cn/i/eg_chinarose.jpg" height="100" width="200" /> </p> </a> <p> 這是第二張圖片,點擊後不會觸發任何跳轉效果<br> <img src="http://www.w3school.com.cn/i/eg_chinarose.jpg" height=200 width=400 /> </p> </body> </html> ''' email.attach_alternative(content=html_content,mimetype="text/html")
# 1.當使用了attach_alternative方法,EmailMultiAlternatives類裏的初始化入參body的值就不會生效了,即郵件正文爲指定的一個html頁面;
# 2.當沒使用attach_alternative方法,EmailMultiAlternatives類裏的初始化入參body的值就會生效了,即郵件正文爲指定的body值(body值的數據類型是字符串);
email.send()
return HttpResponse("【郵件正文值爲一個html頁面+有多個郵件附件】的單個郵件,發送成功啦!")
2.3.第三步:在【helloworld/helloworld/urls.py】裏新增url匹配規則
url(r"^send_email_004/$",views.send_email_004),
2.4.第四步:重啓服務
2.5.第五步:任一瀏覽器上輸入url地址【http://192.168.1.81:8000/send_email_004/】進行訪問後,查看結果
3.相關知識點
3.1.類EmailMultiAlternatives裏的方法【__init__】的源碼簡單分析
class EmailMultiAlternatives(EmailMessage): """ A version of EmailMessage that makes it easy to send multipart/alternative messages. For example, including text and HTML versions of the text is made easier. """ alternative_subtype = 'alternative' def __init__(self, subject='', body='', from_email=None, to=None, bcc=None, connection=None, attachments=None, headers=None, alternatives=None, cc=None, reply_to=None): """ Initialize a single email message (which can be sent to multiple recipients). """ super().__init__( subject, body, from_email, to, bcc, connection, attachments, headers, cc, reply_to, ) self.alternatives = alternatives or []
方法【__init__】裏的幾個主要入參的分析:
- subject: (必填,數據類型爲字符串)郵件標題;
- body: (必填,數據類型爲字符串)郵件正文;
- from_email: (非必填,數據類型爲字符串)發件郵箱;
- to: (非必填,數據類型爲列表)列表中每個值都是一個接收郵件的郵箱地址;
3.2.類EmailMultiAlternatives裏的方法【attach_file】的源碼簡單分析
def attach_file(self, path, mimetype=None): """ Attach a file from the filesystem. Set the mimetype to DEFAULT_ATTACHMENT_MIME_TYPE if it isn't specified and cannot be guessed. For a text/* mimetype (guessed or specified), decode the file's content as UTF-8. If that fails, set the mimetype to DEFAULT_ATTACHMENT_MIME_TYPE and don't decode the content. """ path = Path(path) with path.open('rb') as file: content = file.read() self.attach(path.name, content, mimetype)
從方法【attach_file】的源碼可以大概看出來,其實方法【attach_file】是對方法【attach】的進一步封裝;
3.3.類EmailMultiAlternatives裏的方法【attach】的源碼簡單分析
def attach(self, filename=None, content=None, mimetype=None): """ Attach a file with the given filename and content. The filename can be omitted and the mimetype is guessed, if not provided. If the first parameter is a MIMEBase subclass, insert it directly into the resulting message attachments. For a text/* mimetype (guessed or specified), when a bytes object is specified as content, decode it as UTF-8. If that fails, set the mimetype to DEFAULT_ATTACHMENT_MIME_TYPE and don't decode the content. """ if isinstance(filename, MIMEBase): assert content is None assert mimetype is None self.attachments.append(filename) else: assert content is not None mimetype = mimetype or mimetypes.guess_type(filename)[0] or DEFAULT_ATTACHMENT_MIME_TYPE basetype, subtype = mimetype.split('/', 1) if basetype == 'text': if isinstance(content, bytes): try: content = content.decode() except UnicodeDecodeError: # If mimetype suggests the file is text but it's # actually binary, read() raises a UnicodeDecodeError. mimetype = DEFAULT_ATTACHMENT_MIME_TYPE self.attachments.append((filename, content, mimetype))
截取這部分源碼:
mimetype = mimetype or mimetypes.guess_type(filename)[0] or DEFAULT_ATTACHMENT_MIME_TYPE basetype, subtype = mimetype.split('/', 1)
從這部分源碼可以簡單看出來:當入參mimetype值爲None,django會自動根據附件文件名來推測MIME內容類型的值並賦值給入參mimetype,然後入參mimetype的新值做後續相關處理;
3.4.每個應用的資源存放位置
什麼是資源?比如:一個圖片、一個html頁面、一個css、一個js、一個視頻、一個pdf、一個word、一個txt,等等這些都是不同的資源類型;
每個項目的應用都有對應所屬的資源,那麼每個應用的資源存放位置要怎麼定呢?怎麼定的思路,個人做法主要是這個思路步驟:
- 第一步:每個應用的資源存放位置定爲在每個應用根目錄下的某個手動新增的文件夾,比如該新增的文件夾名爲【public】;
- 第二步:在文件夾【public】裏按不同的資源類型新增對應不同的文件夾,比如新增的文件夾名爲【css】和【word】;
- 第三步:在文件夾【word】裏按不同的數據表/按不同的業務模塊新增對應不同的文件夾,比如新增的文件夾名爲【user】和【test】;
這樣的思路步驟的主要目的是:每個應用的資源在各自應用目錄裏維護,大大減少項目代碼的耦合度,方便後續維護;
以一個應用【hello】爲例,應用【hello】的資源存放位置所對應的具體的文件層級結構大概如下: