smtplib — SMTP 協議客戶端¶
原始碼: Lib/smtplib.py
模組定義了一個 SMTP 客戶端會話物件,該物件可用於將郵件傳送到任何具有 SMTP 或 ESMTP 監聽守護程序的網際網路機器。有關 SMTP 和 ESMTP 操作的詳細資訊,請參閱 RFC 821 (Simple Mail Transfer Protocol) 和 RFC 1869 (SMTP Service Extensions)。smtplib
可用性:非 WASI。
此模組在 WebAssembly 上不起作用或不可用。有關更多資訊,請參閱 WebAssembly 平臺。
- class smtplib.SMTP(host='', port=0, local_hostname=None, [timeout, ]source_address=None)¶
例項封裝了一個 SMTP 連線。它具有支援完整 SMTP 和 ESMTP 操作的方法。如果提供了可選的 host 和 port 引數,則在初始化期間將使用這些引數呼叫 SMTPSMTP
connect()
方法。如果指定了 local_hostname,則在 HELO/EHLO 命令中使用它作為本地主機的 FQDN。否則,將使用socket.getfqdn()
查詢本地主機名。如果connect()
呼叫返回的不是成功程式碼,則會引發SMTPConnectError
。可選的 timeout 引數指定了連線嘗試等阻塞操作的超時(以秒為單位)(如果未指定,則使用全域性預設超時設定)。如果超時,則會引發TimeoutError
。可選的 source_address 引數允許繫結到具有多個網路介面的計算機上的某個特定源地址,以及/或某個特定的源 TCP 埠。它採用一個 2 元組 `(host, port)`,用於連線之前繫結到套接字作為源地址。如果省略(或者如果 host 或 port 分別為 `''` 和/或 `0`),則將使用作業系統預設行為。對於正常使用,您只需要初始化/連線、
sendmail()
和SMTP.quit()
方法。下面提供了一個示例。
類支援SMTP
with
語句。這樣使用時,當with
語句退出時,會自動發出 SMTPQUIT
命令。例如:>>> from smtplib import SMTP >>> with SMTP("domain.org") as smtp: ... smtp.noop() ... (250, b'Ok') >>>
所有命令都將引發一個 審計事件 `smtplib.SMTP.send`,其引數為 `self` 和 `data`,其中 `data` 是即將傳送到遠端主機的資料(位元組)。
版本 3.3 中已更改: 添加了對
with
語句的支援。版本 3.3 中已更改: 添加了 source_address 引數。
版本 3.5 中已新增: 現在支援 SMTPUTF8 擴充套件(RFC 6531)。
版本 3.9 中已更改: 如果 timeout 引數設定為零,則會引發
ValueError
,以防止建立非阻塞套接字。
- class smtplib.SMTP_SSL(host='', port=0, local_hostname=None, \*, [timeout, ]context=None, source_address=None)¶
例項的行為與SMTP_SSL
例項的行為完全相同。SMTP
應用於從連線開始就需要 SSL 且不適合使用SMTP_SSL
starttls()
的情況。如果未指定 host,則使用本地主機。如果 port 為零,則使用標準的 SMTP-over-SSL 埠 (465)。可選引數 local_hostname、timeout 和 source_address 的含義與
類中的相同。context(也是可選的)可以包含一個SMTP
ssl.SSLContext
物件,並允許配置安全連線的各種方面。請閱讀 安全注意事項 以瞭解最佳實踐。版本 3.3 中已更改: 添加了 context 引數。
版本 3.3 中已更改: 添加了 source_address 引數。
在 3.4 版更改: 該類現在支援透過
ssl.SSLContext.check_hostname
進行主機名檢查和*伺服器名稱指示*(參見ssl.HAS_SNI
)。版本 3.9 中已更改: 如果 timeout 引數設定為零,則會引發
ValueError
,以防止建立非阻塞套接字在 3.12 版更改: 已移除已棄用的 keyfile 和 certfile 引數。
- class smtplib.LMTP(host='', port=LMTP_PORT, local_hostname=None, source_address=None[, timeout])¶
LMTP 協議與 ESMTP 非常相似,並且很大程度上基於標準 SMTP 客戶端。通常使用 Unix 套接字進行 LMTP,因此我們的
connect()
方法必須同時支援 Unix 套接字和常規的 host:port 伺服器。可選引數 local_hostname 和 source_address 的含義與
類中的相同。要指定 Unix 套接字,必須為 host 使用絕對路徑,以 '/' 開頭。SMTP
支援身份驗證,使用常規的 SMTP 機制。使用 Unix 套接字時,LMTP 通常不支援或不需要任何身份驗證,但您的具體情況可能有所不同。
版本 3.9 中已更改: 添加了可選的 timeout 引數。
還定義了一系列不錯的異常
- exception smtplib.SMTPException¶
的子類,是此模組提供的所有其他異常的基類。OSError
版本 3.4 中已更改: SMTPException 成為
OSError
的子類
- exception smtplib.SMTPResponseException¶
包含 SMTP 錯誤程式碼的所有異常的基類。當 SMTP 伺服器返回錯誤程式碼時,某些情況下會生成這些異常。
- smtp_code¶
錯誤程式碼。
- smtp_error¶
錯誤訊息。
- exception smtplib.SMTPSenderRefused¶
發件人地址被拒絕。除了所有
SMTPResponseException
異常設定的屬性外,此異常還將 'sender' 設定為 SMTP 伺服器拒絕的字串。
- exception smtplib.SMTPRecipientsRefused¶
所有收件人地址都被拒絕。
- recipients¶
一個字典,其格式與
SMTP.sendmail()
返回的格式完全相同,包含每個收件人的錯誤。
- exception smtplib.SMTPDataError¶
SMTP 伺服器拒絕接受訊息資料。
- exception smtplib.SMTPConnectError¶
在與伺服器建立連線期間發生錯誤。
- exception smtplib.SMTPHeloError¶
伺服器拒絕了我們的
HELO
命令。
- exception smtplib.SMTPNotSupportedError¶
嘗試的命令或選項不受伺服器支援。
在 3.5 版本加入。
- exception smtplib.SMTPAuthenticationError¶
SMTP 身份驗證出錯。最可能的原因是伺服器未接受提供的使用者名稱/密碼組合。
參見
SMTP 物件¶
例項具有以下方法SMTP
- SMTP.set_debuglevel(level)¶
設定除錯輸出級別。對於 level,值為 1 或
True
會導致有關連線以及傳送到伺服器和從伺服器接收到的所有訊息的除錯訊息。值為 2 會導致這些訊息帶有時間戳。版本 3.5 中已更改: 添加了除錯級別 2。
- SMTP.docmd(cmd, args='')¶
向伺服器傳送命令 cmd。可選引數 args 僅用空格將其與命令連線起來。
此方法返回一個由數字響應程式碼和實際響應行組成的 2 元組(多行響應會合併為一行)。
正常操作中,通常不需要顯式呼叫此方法。它用於實現其他方法,並且可能對測試私有擴充套件有用。
如果在等待回覆時與伺服器的連線丟失,將引發
SMTPServerDisconnected
。
- SMTP.connect(host='localhost', port=0)¶
連線到給定埠上的主機。預設值是連線到本地主機上的標準 SMTP 埠 (25)。如果主機名以冒號 (`:`) 加上數字結尾,則會剝離該字尾,並將該數字解釋為要使用的埠號。如果在例項化時指定了主機,則建構函式會自動呼叫此方法。返回伺服器在其連線響應中傳送的響應程式碼和訊息組成的 2 元組。
引發一個 審計事件 `smtplib.connect`,其引數為 `self`、`host` 和 `port`。
- SMTP.helo(name='')¶
使用
HELO
向 SMTP 伺服器標識自己。主機名引數預設為本地主機的完全限定域名。伺服器返回的訊息儲存在物件的helo_resp
屬性中。正常操作中,通常不需要顯式呼叫此方法。它將在必要時由
sendmail()
隱式呼叫。
- SMTP.ehlo(name='')¶
使用
EHLO
向 ESMTP 伺服器標識自己。主機名引數預設為本地主機的完全限定域名。檢查響應以獲取 ESMTP 選項,併為has_extn()
儲存它們。此外,還設定了幾個資訊屬性:伺服器返回的訊息儲存在物件的ehlo_resp
屬性中,does_esmtp
設定為True
或False
(取決於伺服器是否支援 ESMTP),並且esmtp_features
將是一個包含此伺服器支援的 SMTP 服務副檔名稱及其引數(如果有)的字典。除非您希望在傳送郵件之前使用
has_extn()
,否則通常不需要顯式呼叫此方法。它將在必要時由sendmail()
隱式呼叫。
- SMTP.ehlo_or_helo_if_needed()¶
此方法將在本會話中沒有之前的
EHLO
或HELO
命令時呼叫ehlo()
和/或helo()
。它首先嚐試 ESMTPEHLO
。SMTPHeloError
伺服器對
HELO
問候語沒有正確響應。
- SMTP.has_extn(name)¶
如果 name 存在於伺服器返回的 SMTP 服務擴充套件集中,則返回
True
,否則返回False
。忽略大小寫。
- SMTP.verify(address)¶
使用 SMTP
VRFY
檢查此伺服器上地址的有效性。如果使用者地址有效,則返回一個由程式碼 250 和完整的 RFC 822 地址(包括人類可讀的名稱)組成的元組。否則,返回大於或等於 400 的 SMTP 錯誤程式碼和錯誤字串。備註
許多站點會停用 SMTP
VRFY
以阻止垃圾郵件傳送者。
- SMTP.login(user, password, *, initial_response_ok=True)¶
登入到需要身份驗證的 SMTP 伺服器。引數是使用者名稱和用於身份驗證的密碼。如果本會話中沒有先前的
EHLO
或HELO
命令,則此方法會先嚐試 ESMTPEHLO
。如果身份驗證成功,此方法將正常返回,否則可能會引發以下異常:SMTPHeloError
伺服器對
HELO
問候語沒有正確響應。SMTPAuthenticationError
伺服器未接受使用者名稱/密碼組合。
SMTPNotSupportedError
伺服器不支援
AUTH
命令。SMTPException
未找到合適的身份驗證方法。
支援的每種身份驗證方法都會按順序嘗試,前提是伺服器已宣告支援。有關支援的身份驗證方法的列表,請參閱smtplib
auth()
。initial_response_ok 引數會傳遞給auth()
。可選關鍵字引數 initial_response_ok 指定對於支援它的身份驗證方法,是否可以將 RFC 4954 中指定的“初始響應”與
AUTH
命令一起傳送,而不是要求質詢/響應。版本 3.5 中已更改: 可能會引發
SMTPNotSupportedError
,並添加了 initial_response_ok 引數。
- SMTP.auth(mechanism, authobject, *, initial_response_ok=True)¶
發出指定的身份驗證 mechanism 的
SMTP
AUTH
命令,並透過 authobject 處理質詢響應。mechanism 指定用作
AUTH
命令引數的身份驗證機制;有效值是esmtp_features
中 `auth` 元素列出的值。authobject 必須是一個可呼叫物件,它接受一個可選的單個引數
data = authobject(challenge=None)
如果可選關鍵字引數 initial_response_ok 為 true,則會先用無引數呼叫 `authobject()`。它可以返回 RFC 4954 的“初始響應”ASCII
str
,它將作為下面的AUTH
命令進行編碼和傳送。如果 `authobject()` 不支援初始響應(例如,因為它需要質詢),則在呼叫時應返回None
(當 `challenge=None` 時)。如果 initial_response_ok 為 false,則不會先用 `None` 呼叫 `authobject()`。如果初始響應檢查返回
None
,或者 initial_response_ok 為 false,則將呼叫 `authobject()` 來處理伺服器的質詢響應;傳遞給它的 challenge 引數將是一個bytes
。它應該返回 ASCIIstr
data,它將被 base64 編碼併發送到伺服器。
類為 `CRAM-MD5`、`PLAIN` 和 `LOGIN` 機制提供了 `authobjects`;它們分別命名為 `SMTP.auth_cram_md5`、`SMTP.auth_plain` 和 `SMTP.auth_login`。它們都需要將 `SMTP` 例項的 `user` 和 `password` 屬性設定為適當的值。SMTP
使用者程式碼通常不需要直接呼叫 `auth`,而是可以呼叫 `login()` 方法,該方法將按列出的順序嘗試上述每個機制。`auth` 是公開的,以便於實現 `smtplib` 未(或尚未)直接支援的身份驗證方法的實現。
在 3.5 版本加入。
- SMTP.starttls(*, context=None)¶
將 SMTP 連線置於 TLS (Transport Layer Security) 模式。之後的所有 SMTP 命令都將進行加密。之後應再次呼叫
ehlo()
。如果提供了 keyfile 和 certfile,則它們用於建立
ssl.SSLContext
。可選的 context 引數是一個
ssl.SSLContext
物件;這是使用 keyfile 和 certfile 的替代方法,如果指定了它,則 keyfile 和 certfile 都應為None
。如果本會話中沒有先前的
EHLO
或HELO
命令,則此方法會先嚐試 ESMTPEHLO
。在 3.12 版更改: 已移除已棄用的 keyfile 和 certfile 引數。
SMTPHeloError
伺服器對
HELO
問候語沒有正確響應。SMTPNotSupportedError
伺服器不支援 STARTTLS 擴充套件。
RuntimeError
您的 Python 直譯器沒有可用的 SSL/TLS 支援。
版本 3.3 中已更改: 添加了 context 引數。
版本 3.4 中已更改: 該方法現在支援使用
ssl.SSLContext.check_hostname
和 *伺服器名稱指示*(參見HAS_SNI
)進行主機名檢查。版本 3.5 中已更改: 缺乏 STARTTLS 支援時引發的異常現在是
SMTPNotSupportedError
子類,而不是基類SMTPException
。
- SMTP.sendmail(from_addr, to_addrs, msg, mail_options=(), rcpt_options=())¶
傳送郵件。必需的引數是 RFC 822 發件人地址字串、一個 RFC 822 收件人地址字串列表(單個字串將被視為包含 1 個地址的列表)以及一個訊息字串。呼叫者可以為用於 `MAIL FROM` 命令的郵件信封傳遞一個 ESMTP 選項列表(例如 `8bitmime`),作為 mail_options。可作為 rcpt_options 傳遞給所有 `RCPT` 命令的 ESMTP 選項(例如 `DSN` 命令)。(如果需要對不同收件人使用不同的 ESMTP 選項,則必須使用低階方法,如 `mail()`、`rcpt()` 和 `data()` 來發送訊息。)
備註
from_addr 和 to_addrs 引數用於構造傳輸代理使用的郵件信封。`sendmail` 不會以任何方式修改訊息頭。
msg 可以是一個包含 ASCII 範圍字元的字串,或者是一個位元組字串。字串使用 ascii 編碼器編碼為位元組,並且單個 `\r` 和 `\n` 字元將被轉換為 `\r\n` 字元。位元組字串不會被修改。
如果本會話中沒有先前的
EHLO
或HELO
命令,則此方法會先嚐試 ESMTPEHLO
。如果伺服器支援 ESMTP,則訊息大小和指定的每個選項都將傳遞給它(如果該選項在伺服器宣告的功能集中)。如果 `EHLO` 失敗,則會嘗試 `HELO` 並抑制 ESMTP 選項。如果郵件被至少一個收件人接受,此方法將正常返回。否則,它將引發異常。也就是說,如果此方法不引發異常,那麼您的郵件應該會送達。如果此方法不引發異常,它將返回一個字典,其中包含每個被拒絕的收件人條目。每個條目包含一個 SMTP 錯誤程式碼及其由伺服器傳送的附帶錯誤訊息的元組。
如果 `SMTPUTF8` 包含在 mail_options 中,並且伺服器支援它,則 from_addr 和 to_addrs 可以包含非 ASCII 字元。
此方法可能會引發以下異常:
SMTPRecipientsRefused
所有收件人都被拒絕。沒有人收到郵件。
SMTPHeloError
伺服器對
HELO
問候語沒有正確響應。SMTPSenderRefused
伺服器未接受 from_addr。
SMTPDataError
伺服器返回了意外錯誤程式碼(除了拒絕收件人之外)。
SMTPNotSupportedError
`SMTPUTF8` 已在 mail_options 中給出,但伺服器不支援。
除非另有說明,否則即使引發了異常,連線也會保持開啟狀態。
版本 3.2 中已更改: msg 可以是位元組字串。
版本 3.5 中已更改: 添加了 `SMTPUTF8` 支援,並且如果指定了 `SMTPUTF8` 但伺服器不支援,則可能引發
SMTPNotSupportedError
。
- SMTP.send_message(msg, from_addr=None, to_addrs=None, mail_options=(), rcpt_options=())¶
這是一個方便的方法,用於呼叫
sendmail()
,其中訊息由email.message.Message
物件表示。引數的含義與sendmail()
相同,只是 msg 是一個 `Message` 物件。如果 from_addr 是
None
或 to_addrs 是None
,則 `send_message` 會根據 RFC 5322 中指定的 msg 的頭部欄位提取地址來填充這些引數:from_addr 設定為 `Sender` 欄位(如果存在),否則設定為 `From` 欄位。to_addrs 組合了 msg 中 `To`、`Cc` 和 `Bcc` 欄位的值(如果有)。如果訊息中存在恰好一對 `Resent-*` 頭部,則忽略常規頭部,而是使用 `Resent-*` 頭部。如果訊息包含多對 `Resent-*` 頭部,則會引發ValueError
,因為無法明確檢測到最近的 `Resent-` 頭部集。`send_message` 使用
BytesGenerator
將 msg 序列化,將 `\r\n` 作為 *linesep*,並呼叫sendmail()
來傳輸生成的郵件。無論 from_addr 和 to_addrs 的值如何,`send_message` 都不會傳輸 msg 中可能存在的任何 `Bcc` 或 `Resent-Bcc` 頭部。如果 from_addr 和 to_addrs 中的任何地址包含非 ASCII 字元且伺服器未宣告 `SMTPUTF8` 支援,則會引發SMTPNotSupportedError
。否則,將使用其policy
的克隆(將utf8
屬性設定為True
)來序列化 `Message`,並將 `SMTPUTF8` 和 `BODY=8BITMIME` 新增到 mail_options 中。在 3.2 版本加入。
版本 3.5 中已新增: 支援國際化地址(`SMTPUTF8`)。
- SMTP.quit()¶
終止 SMTP 會話並關閉連線。返回 SMTP
QUIT
命令的結果。
還支援與標準 SMTP/ESMTP 命令 `HELP`、`RSET`、`NOOP`、`MAIL`、`RCPT` 和 `DATA` 對應的低階方法。通常不需要直接呼叫它們,因此此處不予記錄。有關詳細資訊,請參閱模組程式碼。
此外,SMTP 例項具有以下屬性
SMTP 示例¶
此示例提示使用者輸入郵件信封所需的地址(“To”和“From”地址)以及要傳遞的訊息。請注意,要包含在訊息中的頭部必須作為輸入包含在訊息中;此示例不處理 RFC 822 頭部。特別是,“To”和“From”地址必須在訊息頭部中顯式包含
import smtplib
def prompt(title):
return input(title).strip()
from_addr = prompt("From: ")
to_addrs = prompt("To: ").split()
print("Enter message, end with ^D (Unix) or ^Z (Windows):")
# Add the From: and To: headers at the start!
lines = [f"From: {from_addr}", f"To: {', '.join(to_addrs)}", ""]
while True:
try:
line = input()
except EOFError:
break
else:
lines.append(line)
msg = "\r\n".join(lines)
print("Message length is", len(msg))
server = smtplib.SMTP("localhost")
server.set_debuglevel(1)
server.sendmail(from_addr, to_addrs, msg)
server.quit()
備註
通常,您將希望使用 `email` 包的特性來構造電子郵件訊息,然後可以透過 `send_message()` 進行傳送;參見 email: 示例。