本文首發於公眾號:Hunter後端
原文連結:Django筆記三十八之傳送郵件
這一篇筆記介紹如何在 Django 中傳送郵件。
在 Python 中,提供了 smtplib 的郵件模組,而 Django 在這個基礎上對其進行了封裝,我們可以通過 django.core.mail
來呼叫。
以下是本篇筆記的目錄:
在正式傳送郵件前,我們需要在 settings.py 裡設定幾個引數,如下:
# hunter/settings.py
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.163.com'
EMAIL_PORT = 465
EMAIL_HOST_USER = '[email protected]'
EMAIL_HOST_PASSWORD = 'JBDMVIXSHYxxxxx'
EMAIL_USE_SSL = True
EMAIL_USE_TLS = False
這些設定項在 log 紀錄檔記錄那一篇筆記中有過介紹,那是我們指定紀錄檔等級傳送郵件的功能,這裡再做一下簡單的介紹。
EMAIL_BACKEND 是我們指定的郵箱後端,在後面我們會介紹在開發偵錯階段的時候可以設定的其他值
EMAIL_HOST 傳送郵箱的主機地址,這裡我們使用的是 163 郵箱的地址
EMAIL_PORT EMAIL_HOST 使用的埠
EMAIL_HOST_USER 發件人郵箱地址
EMAIL_HOST_PASSWORD 163 郵箱開啟了 SMTP 服務提供的授權碼
EMAIL_USE_SSL 與 SMTP 伺服器對話時是否使用隱式 TLS 連線,這種型別被稱為 SSL,通常在 465 埠使用,這個欄位與 EMAIL_USE_TLS 是互相排斥的,只能設定一個為 True
EMAIL_USE_TLS 與 SMTP 伺服器對話是否使用 TLS 連線,一般在 587 埠
以上就是在 Django 裡使用 163 郵箱的一個設定項範例。
設定好之後我們就可以嘗試傳送一下郵件,最簡單的使用範例如下:
from django.core.mail import send_mail
send_mail(
subject="subject 主題",
message="郵件主體",
from_email="[email protected]",
recipient_list=["[email protected]"],
)
在上面的呼叫中,subject 是傳送的郵件的標題,
message 是郵件傳送的正文內容。
from_email 是傳送郵件的郵箱
recipient_list 是接收收件人列表,可以接收多個郵箱地址
對於 message 引數,接收的是純文字資訊,會將引數內容直接顯示在郵件正文,如果是想對文字進行更多操作,比如加大字型,加粗,或者加上表格等操作,可以使用 html_message
引數來替代 message 引數。
比如:
send_mail(
subject="subject 主題",
from_email="[email protected]",
recipient_list=["[email protected]"],
html_message="<h1>html main body</h1>"
)
在這裡,html_message
將引數內容當作一個 html 文字進行解析,傳送郵件後就可以在接收郵箱看到大號的文字字型了。
如果有批次傳送郵件的需求,可以使用 send_mass_mail
方法。
from django.core.mail import send_mass_mail
message_1 = ("郵件標題1", "郵件正文1", "[email protected]", ["[email protected]"])
message_2 = ("郵件標題2", "郵件正文2", "[email protected]", ["[email protected]"])
send_mass_mail(
(message_1, message_2)
該方法接收列表引數,其中列表的每一個元素的引數和引數順序都是固定的,分別是郵件標題,正文,郵件傳送人,和郵件接收人列表。
注意: 因為批次傳送的引數是固定的,所以並不支援 send_mail 裡的 html_message
引數。
前面介紹的 send_mail() 方法簡單可用,但是並不支援郵件裡的附件、抄送等功能,接下來我們使用 EmailMessage 這個類來實現這些額外的功能。
以下是使用 EmailMessage 實現傳送郵件的簡單範例:
from django.core.mail import EmailMessage
email = EmailMessage(
subject="郵件標題",
body="郵件主體",
from_email="[email protected]",
to=["[email protected]"],
)
email.send()
引數名稱與 send_mail() 略有不同,這裡的郵件正文是 body,接收人列表為 to。
這裡在範例化 EmailMessage 之後,呼叫 send() 方法即可傳送郵件。
除了上面的這些引數,還有 bcc
,實現的是密送功能,也是郵件接收人列表,cc
是抄送人列表。
還有 attachments
引數,實現的是附件功能,接下來介紹幾種傳送附件的方式:
我們可以直接在 EmailMessage() 中新增附件引數,attachments 引數接收一個列表,列表元素也是一個列表,內層的這個列表接收三個元素,第一個元素為檔名,第二個元素為檔案內容,第三個元素為指定的附件的 MIME 型別,第三個引數省略的話就會參考附件的檔名自動選擇。
我們在系統根目錄下建立兩個檔案 a.txt, b.txt,然後實現範例如下:
from django.core.mail import EmailMessage
attachments = []
for file_name in ["./a.txt", "./b.txt"]:
with open(file_name, "r") as f:
content = f.read()
attachments.append((file_name, content))
email = EmailMessage(
subject="郵件標題",
body="郵件主體",
from_email="[email protected]",
to=["[email protected]"],
attachments=attachments,
)
email.send()
除了直接在 EmailMessage 範例中新增引數,我們還可以使用 attach() 方法。
範例如下:
email = EmailMessage(
subject="郵件標題",
body="郵件主體",
from_email="[email protected]",
to=["[email protected]"],
)
file_name_1 = "./a.txt"
f = open(file_name_1, "r")
file_content_1 = f.read()
f.close()
email.attach(file_name_1, file_content_1)
email.send()
還有一個方式是使用 attach_file() 方法,引數內容是檔案路徑+檔名,系統會自動為我們解析該檔案:
email = EmailMessage(
subject="郵件標題",
body="郵件主體",
from_email="[email protected]",
to=["[email protected]"],
)
email.attach_file("./b.txt")
email.send()
前面介紹了在 send_mail() 方法可以通過 html_message 的引數傳送 html 頁面的郵件,在 EmailMessage 也可以實現,但是需要修改 content_subtype 屬性。
預設情況下,EmailMessage.content_subtype
是 "plain",我們將其改為 "html" 即可傳送 html 頁面的郵件。
email = EmailMessage(
subject="郵件標題",
body="<h1>郵件主體</h1>",
from_email="[email protected]",
to=["[email protected]"],
)
email.content_subtype = "html"
email.send()
因為傳送郵件涉及到網路連線及可能存在的大量資料的傳送,比如附件。
所以,如果是在介面中有傳送郵件的需求,我們可以通過 celery 的非同步任務實現傳送郵件的功能。
而郵件的傳送會涉及到 SMTP 連線的建立和關閉,所以複用連線也是一個好的方式。
這裡介紹兩種方式:
send_messages() 方法接收 EmailMessage 範例列表,然後實現批次傳送的功能:
from django.core import mail
from django.core.mail import EmailMessage
email_1 = EmailMessage(
subject="郵件標題1",
body="郵件主體1",
from_email="[email protected]",
to=["[email protected]"],
)
email_2 = EmailMessage(
subject="郵件標題2",
body="郵件主體2",
from_email="[email protected]",
to=["[email protected]"],
)
connection = mail.get_connection()
messages = [email_1, email_2]
connection.send_messages(messages)
我們可以手動控制 connection 的建立和關閉。
from django.core import mail
connection = mail.get_connection()
email_1 = mail.EmailMessage(
subject="郵件標題1",
body="郵件主體1",
from_email="[email protected]",
to=["[email protected]"],
connection=connection
)
email_1.send()
email_2 = mail.EmailMessage(
subject="郵件標題2",
body="郵件主體2",
from_email="[email protected]",
to=["[email protected]"],
)
email_3 = mail.EmailMessage(
subject="郵件標題3",
body="郵件主體3",
from_email="[email protected]",
to=["[email protected]"],
)
messages = [email_2, email_3]
connection.send_messages(messages)
connection.close()
在這裡,email_1 的呼叫增加了 connection 引數,email_2 和 email_3 也是使用 connection 進行的批次傳送
這個過程中,connection 一直沒有關閉,所以複用的是同一個連線,直到最後呼叫 close() 才算是手動關閉了這個 connection 連線。
在開發階段,我們偵錯傳送郵件功能的時候,有時候並不想每次都真的傳送郵件給指定賬戶,儘管可能是測試賬號,我們有時候只想看一下輸出的內容,可以更改郵箱設定的後端
我們可以在 settings.py 裡設定:
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
這樣,在呼叫我們前面的 send 方法後,系統就不會傳送郵件給 to 的接收人列表了,而是會在控制檯輸出我們的郵件資訊:
類似如下:
Content-Type: text/html; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit
Subject: =?utf-8?b?6YKu5L2qCH6aKY?=
From: [email protected]
To: [email protected]
Date: Fri, 17 Feb 2023 18:01:21 -0000
Message-ID:
<167665688132.1114.884170460108140763@1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa>
<h1>郵件主體</h1>
-------------------------------------------------------------------------------
在偵錯階段,我們還可以指定將郵件的內容輸出到檔案,同樣的修改郵件後端設定:
EMAIL_BACKEND = 'django.core.mail.backends.filebased.EmailBackend'
EMAIL_FILE_PATH = './emails_file'
這裡設定了郵件後端為檔案,EMAIL_FILE_PATH 則是指定了郵件內容放到系統根目錄下的 emails_file 檔案中。
呼叫了傳送郵件的函數後,在這個資料夾下就會多出一個檔案,檔案內容是我們前面在 console 控制檯輸出的內容
如果想獲取更多後端相關文章,可掃碼關注閱讀: