smtplib --- SMTP 協(xié)議客戶(hù)端?

源代碼: Lib/smtplib.py


smtplib 模塊定義了一個(gè) SMTP 客戶(hù)端會(huì )話(huà)對象,該對象可將郵件發(fā)送到互聯(lián)網(wǎng)上任何帶有 SMTP 或 ESMTP 監聽(tīng)程序的計算機。 關(guān)于 SMTP 和 ESMTP 操作的更多細節請參閱 RFC 821 (簡(jiǎn)單郵件傳輸協(xié)議) 和 RFC 1869 (SMTP 服務(wù)擴展)。

class smtplib.SMTP(host='', port=0, local_hostname=None, [timeout, ]source_address=None)?

SMTP 實(shí)例是對 SMTP 連接的封裝。 它提供了支持各種 SMTP 和 ESMTP 操作的方法。 如果給出了可選的 host 和 port 形參,則會(huì )在初始化期間調用 SMTP connect() 方法并附帶這些形參。 如果指定了 local_hostname,它將在 HELO/EHLO 命令中被用作本地主機的 FQDN。 在其他情況下,會(huì )使用 socket.getfqdn() 來(lái)找到本地主機名。 如果 connect() 調用返回了表示成功的代碼以外的信息,則會(huì )引發(fā) SMTPConnectError。 可選的 timeout 形參指定了阻塞操作如連接嘗試的超時(shí)秒數(如果未指定,則將使用全局默認超時(shí)設置)。 如果達到超時(shí)限制,則會(huì )引發(fā) TimeoutError。 可選的 source_address 形參允許在在有多張網(wǎng)卡的計算機中綁定到某些特定的源地址,和/或綁定到某些特定的源 TCP 端口。 它接受一個(gè) 2 元組 (host, port) 作為在連接之前所綁定作為其源地址的套接字。 如果省略(或者如果 host 或 port 為 '' 和/或分別為 0)則將使用 OS 的默認行為。

正常使用時(shí),只需要初始化或 connect 方法,sendmail() 方法,再加上 SMTP.quit() 方法即可。下文包括了一個(gè)示例。

SMTP 類(lèi)支持 with 語(yǔ)句。當這樣使用時(shí),with 語(yǔ)句一退出就會(huì )自動(dòng)發(fā)出 SMTP QUIT 命令。例如:

>>>
>>> from smtplib import SMTP
>>> with SMTP("domain.org") as smtp:
...     smtp.noop()
...
(250, b'Ok')
>>>

引發(fā)一個(gè) 審計事件 smtplib.send,附帶參數 self, data。

在 3.3 版更改: 添加了對 with 語(yǔ)句的支持。

在 3.3 版更改: 添加了 source_address 參數。

3.5 新版功能: 現在已支持 SMTPUTF8 擴展 (RFC 6531)。

在 3.9 版更改: 如果 timeout 形參被設為零,則它將引發(fā) ValueError 來(lái)阻止創(chuàng )建非阻塞的套接字

class smtplib.SMTP_SSL(host='', port=0, local_hostname=None, keyfile=None, certfile=None, [timeout, ]context=None, source_address=None)?

SMTP_SSL 實(shí)例與 SMTP 實(shí)例的行為完全相同。在開(kāi)始連接就需要 SSL,且 starttls() 不適合的情況下,應該使用 SMTP_SSL。如果未指定 host,則使用 localhost。如果 port 為 0,則使用標準 SMTP-over-SSL 端口(465)??蛇x參數 local_hostname、timeoutsource_address 的含義與 SMTP 類(lèi)中的相同??蛇x參數 context 是一個(gè) SSLContext 對象,可以從多個(gè)方面配置安全連接。請閱讀 安全考量 以獲取最佳實(shí)踐。

keyfilecertfilecontext 的傳統替代物,它們可以指向 PEM 格式的私鑰和證書(shū)鏈文件用于 SSL 連接。

在 3.3 版更改: 增加了 context。

在 3.3 版更改: 添加了 source_address 參數。

在 3.4 版更改: 本類(lèi)現在支持使用 ssl.SSLContext.check_hostname服務(wù)器名稱(chēng)指示 (參閱 ssl.HAS_SNI)進(jìn)行主機名檢查。

3.6 版后已移除: keyfilecertfile 已棄用并轉而推薦 context。 請改用 ssl.SSLContext.load_cert_chain() 或讓 ssl.create_default_context() 為你選擇系統所信任的 CA 證書(shū)。

在 3.9 版更改: 如果 timeout 形參被設為零,則它將引發(fā) ValueError 來(lái)阻止創(chuàng )建非阻塞的套接字

class smtplib.LMTP(host='', port=LMTP_PORT, local_hostname=None, source_address=None[, timeout])?

LMTP 協(xié)議與 ESMTP 非常相似,它很大程度上基于標準的 SMTP 客戶(hù)端。將 Unix 套接字用于 LMTP 是很常見(jiàn)的,因此 connect() 方法支持 Unix 套接字,也支持常規的 host:port 服務(wù)器??蛇x參數 local_hostname 和 source_address 的含義與 SMTP 類(lèi)中的相同。要指定 Unix 套接字,host 必須使用絕對路徑,以 '/' 開(kāi)頭。

支持使用常規的 SMTP 機制來(lái)進(jìn)行認證。 當使用 Unix 套接字時(shí),LMTP 通常不支持或要求任何認證,但你的情況可能會(huì )有所不同。

在 3.9 版更改: 添加了可選的 timeout 形參。

同樣地定義了一組精心選擇的異常:

exception smtplib.SMTPException?

OSError 的子類(lèi),它是本模塊提供的所有其他異常的基類(lèi)。

在 3.4 版更改: SMTPException 已成為 OSError 的子類(lèi)

exception smtplib.SMTPServerDisconnected?

當服務(wù)器意外斷開(kāi)連接,或在 SMTP 實(shí)例連接到服務(wù)器之前嘗試使用它時(shí)將引發(fā)此異常。

exception smtplib.SMTPResponseException?

包括 SMTP 錯誤代碼的所有異常的基類(lèi)。 這些異常會(huì )在 SMTP 服務(wù)器返回錯誤代碼時(shí)在實(shí)例中生成。 錯誤代碼存放在錯誤的 smtp_code 屬性中,并且 smtp_error 屬性會(huì )被設為錯誤消息。

exception smtplib.SMTPSenderRefused?

發(fā)送方地址被拒絕。 除了在所有 SMTPResponseException 異常上設置的屬性,還會(huì )將 'sender' 設為代表拒絕方 SMTP 服務(wù)器的字符串。

exception smtplib.SMTPRecipientsRefused?

所有接收方地址被拒絕。 每個(gè)接收方的錯誤可通過(guò)屬性 recipients 來(lái)訪(fǎng)問(wèn),該屬性是一個(gè)字典,其元素順序與 SMTP.sendmail() 所返回的一致。

exception smtplib.SMTPDataError?

SMTP 服務(wù)器拒絕接收消息數據。

exception smtplib.SMTPConnectError?

在建立與服務(wù)器的連接期間發(fā)生了錯誤。

exception smtplib.SMTPHeloError?

服務(wù)器拒絕了我們的 HELO 消息。

exception smtplib.SMTPNotSupportedError?

嘗試的命令或選項不被服務(wù)器所支持。

3.5 新版功能.

exception smtplib.SMTPAuthenticationError?

SMTP 認證出現問(wèn)題。 最大的可能是服務(wù)器不接受所提供的用戶(hù)名/密碼組合。

參見(jiàn)

RFC 821 - 簡(jiǎn)單郵件傳輸協(xié)議

SMTP 的協(xié)議定義。 該文件涵蓋了 SMTP 的模型、操作程序和協(xié)議細節。

RFC 1869 - SMTP 服務(wù)擴展

定義了 SMTP 的 ESMTP 擴展。 這描述了一個(gè)用新命令擴展 SMTP 的框架,支持動(dòng)態(tài)發(fā)現服務(wù)器所提供的命令,并定義了一些額外的命令。

SMTP 對象?

一個(gè) SMTP 實(shí)例擁有以下方法:

SMTP.set_debuglevel(level)?

設置調試輸出級別。 如果 level 的值為 1 或 True ,就會(huì )產(chǎn)生連接的調試信息,以及所有發(fā)送和接收服務(wù)器的信息。 如果 level 的值為 2 ,則這些信息會(huì )被加上時(shí)間戳。

在 3.5 版更改: 添調試級別 2 。

SMTP.docmd(cmd, args='')?

向服務(wù)器發(fā)送一條命令 cmd 。 可選的參數 args 被簡(jiǎn)單地串聯(lián)到命令中,用一個(gè)空格隔開(kāi)。

這將返回一個(gè)由數字響應代碼和實(shí)際響應行組成的2元組(多行響應被連接成一個(gè)長(cháng)行)。

在正常操作中,應該沒(méi)有必要明確地調用這個(gè)方法。它被用來(lái)實(shí)現其他方法,對于測試私有擴展可能很有用。

如果在等待回復的過(guò)程中,與服務(wù)器的連接丟失, SMTPServerDisconnected 將被觸發(fā)。

SMTP.connect(host='localhost', port=0)?

連接到某個(gè)主機的某個(gè)端口。默認是連接到 localhost 的標準 SMTP 端口(25)上。如果主機名以冒號 (':') 結尾,后跟數字,則該后綴將被刪除,且數字將視作要使用的端口號。如果在實(shí)例化時(shí)指定了 host,則構造函數會(huì )自動(dòng)調用本方法。返回包含響應碼和響應消息的 2 元組,它們由服務(wù)器在其連接響應中發(fā)送。

觸發(fā)一個(gè) auditing event smtplib.connect,其參數為 self , host , port 。

SMTP.helo(name='')?

使用 HELO 向 SMTP 服務(wù)器表明自己的身份。 hostname 參數默認為本地主機的完全合格域名。服務(wù)器返回的消息被存儲為對象的 helo_resp 屬性。

在正常操作中,應該沒(méi)有必要明確調用這個(gè)方法。它將在必要時(shí)被 sendmail() 隱式調用。

SMTP.ehlo(name='')?

使用 EHLO 向 ESMTP 服務(wù)器表明自己的身份。 hostname 參數默認為本地主機的完全合格域名。 檢查 ESMTP 選項的響應,并存儲它們供 has_extn() 使用。同時(shí)設置幾個(gè)信息屬性:服務(wù)器返回的消息被存儲為 ehlo_resp 屬性, does_esmtp 根據服務(wù)器是否支持 ESMTP 被設置為 TrueFalse ,而 esmtp_features 將是一個(gè)字典,包含這個(gè)服務(wù)器支持的 SMTP 服務(wù)擴展的名稱(chēng),以及它們的參數(如果有)。

除非你想在發(fā)送郵件前使用 has_extn() ,否則應該沒(méi)有必要明確調用這個(gè)方法。 它將在必要時(shí)被 sendmail() 隱式調用。

SMTP.ehlo_or_helo_if_needed()?

如果這個(gè)會(huì )話(huà)中沒(méi)有先前的 EHLOHELO 命令,該方法會(huì )調用 ehlo() 和/或 helo() 。它首先嘗試 ESMTP EHLO 。

SMTPHeloError

服務(wù)器沒(méi)有正確回復 HELO 問(wèn)候。

SMTP.has_extn(name)?

如果 name 在服務(wù)器返回的 SMTP 服務(wù)擴展集合中,返回 True ,否則為 False 。大小寫(xiě)被忽略。

SMTP.verify(address)?

使用 SMTP VRFY 檢查此服務(wù)器上的某個(gè)地址是否有效。 如果用戶(hù)地址有效則返回一個(gè)由代碼 250 和完整 RFC 822 地址(包括人名)組成的元組。 否則返回 400 或更大的 SMTP 錯誤代碼以及一個(gè)錯誤字符串。

備注

許多網(wǎng)站都禁用 SMTP VRFY 以阻止垃圾郵件。

SMTP.login(user, password, *, initial_response_ok=True)?

登錄到一個(gè)需要認證的 SMTP 服務(wù)器。 參數是用于認證的用戶(hù)名和密碼。 如果會(huì )話(huà)在之前沒(méi)有執行過(guò) EHLOHELO 命令,此方法會(huì )先嘗試 ESMTP EHLO。 如果認證成功則此方法將正常返回,否則可能引發(fā)以下異常:

SMTPHeloError

服務(wù)器沒(méi)有正確回復 HELO 問(wèn)候。

SMTPAuthenticationError

服務(wù)器不接受所提供的用戶(hù)名/密碼組合。

SMTPNotSupportedError

服務(wù)器不支持 AUTH 命令。

SMTPException

未找到適當的認證方法。

smtplib 所支持的每種認證方法只要被服務(wù)器聲明支持就會(huì )被依次嘗試。 請參閱 auth() 獲取受支持的認證方法列表。 initial_response_ok 會(huì )被傳遞給 auth()。

可選的關(guān)鍵字參數 initial_response_ok 對于支持它的認證方法,是否可以與 AUTH 命令一起發(fā)送 RFC 4954 中所規定的“初始響應”,而不是要求回復/響應。

在 3.5 版更改: 可能會(huì )引發(fā) SMTPNotSupportedError,并添加 initial_response_ok 形參。

SMTP.auth(mechanism, authobject, *, initial_response_ok=True)?

為指定的認證機制 mechanism 發(fā)送 SMTP AUTH 命令,并通過(guò) authobject 處理回復響應。

mechanism 指定要使用何種認證機制作為 AUTH 命令的參數;可用的值是在 esmtp_featuresauth 元素中列出的內容。

authobject 必須是接受一個(gè)可選的單獨參數的可調用對象:

data = authobject(challenge=None)

如果可選的關(guān)鍵字參數 initial_response_ok 為真值,則將先不帶參數地調用 authobject()。 它可以返回 RFC 4954 "初始響應" ASCII str,其內容將被編碼并使用下述的 AUTH 命令來(lái)發(fā)送。 如果 authobject() 不支持初始響應(例如由于要求一個(gè)回復),它應當將 None 作為附帶 challenge=None 調用的返回值。 如果 initial_response_ok 為假值,則 authobject() 將不會(huì )附帶 None 被首先調用。

如果初始響應檢測返回了 None,或者如果 initial_response_ok 為假值,則將調用 authobject() 來(lái)處理服務(wù)器的回復響應;它所傳遞的 challenge 參數將為一個(gè) bytes。 它應當返回用 base64 進(jìn)行編碼的 ASCII str data 并發(fā)送給服務(wù)器。

SMTP 類(lèi)提供的 authobjects 針對 CRAM-MD5, PLAINLOGIN 等機制;它們的名稱(chēng)分別是 SMTP.auth_cram_md5, SMTP.auth_plainSMTP.auth_login。 它們都要求將 userpassword 這兩個(gè) SMTP 實(shí)例屬性設為適當的值。

用戶(hù)代碼通常不需要直接調用 auth,而是調用 login() 方法,它將按上述順序依次嘗試上述每一種機制。 auth 被公開(kāi)以便輔助實(shí)現 smtplib 沒(méi)有(或尚未)直接支持的認證方法。

3.5 新版功能.

SMTP.starttls(keyfile=None, certfile=None, context=None)?

將 SMTP 連接設為 TLS (傳輸層安全) 模式。 后續的所有 SMTP 命令都將被加密。 你應當隨即再次調用 ehlo()。

如果提供了 keyfilecertfile,它們會(huì )被用來(lái)創(chuàng )建 ssl.SSLContext。

可選的 context 形參是一個(gè) ssl.SSLContext 對象;它是使用密鑰文件和證書(shū)的替代方式,如果指定了該形參則 keyfilecertfile 都應為 None。

如果這個(gè)會(huì )話(huà)中沒(méi)有先前的 EHLO or HELO 命令,該方法會(huì )首先嘗試 ESMTP EHLO。

3.6 版后已移除: keyfilecertfile 已棄用并轉而推薦 context。 請改用 ssl.SSLContext.load_cert_chain() 或讓 ssl.create_default_context() 為你選擇系統所信任的 CA 證書(shū)。

SMTPHeloError

服務(wù)器沒(méi)有正確回復 HELO 問(wèn)候。

SMTPNotSupportedError

服務(wù)器不支持 STARTTLS 擴展。

RuntimeError

SSL/TLS 支持在你的 Python 解釋器上不可用。

在 3.3 版更改: 增加了 context。

在 3.4 版更改: 此方法現在支持使用 SSLContext.check_hostname服務(wù)器名稱(chēng)指示符 (參見(jiàn) HAS_SNI) 進(jìn)行主機名檢查。

在 3.5 版更改: 因缺少 STARTTLS 支持而引發(fā)的錯誤現在是 SMTPNotSupportedError 子類(lèi)而不是 SMTPException 基類(lèi)。

SMTP.sendmail(from_addr, to_addrs, msg, mail_options=(), rcpt_options=())?

發(fā)送郵件。必要參數是一個(gè) RFC 822 發(fā)件地址字符串,一個(gè) RFC 822 收件地址字符串列表(裸字符串將被視為含有 1 個(gè)地址的列表),以及一個(gè)消息字符串。調用者可以將 ESMTP 選項列表(如 8bitmime)作為 mail_options 傳入,用于 MAIL FROM 命令。需要與所有 RCPT 命令一起使用的 ESMTP 選項(如 DSN 命令)可以作為 rcpt_options 傳入。(如果需要對不同的收件人使用不同的 ESMTP 選項,則必須使用底層的方法來(lái)發(fā)送消息,如 mail(), rcpt()data()。)

備注

from_addrto_addrs 形參被用來(lái)構造傳輸代理所使用的消息封包。 sendmail 不會(huì )以任何方式修改消息標頭。

msg 可以是一個(gè)包含 ASCII 范圍內字符的字符串,或是一個(gè)字節串。 字符串會(huì )使用 ascii 編解碼器編碼為字節串,并且單獨的 \r\n 字符會(huì )被轉換為 \r\n 字符序列。 字節串則不會(huì )被修改。

如果在此之前本會(huì )話(huà)沒(méi)有執行過(guò) EHLOHELO 命令,此方法會(huì )先嘗試 ESMTP EHLO。 如果服務(wù)器執行了 ESMTP,消息大小和每個(gè)指定的選項將被傳遞給它(如果指定的選項屬于服務(wù)器聲明的特性集)。 如果 EHLO 失敗,則將嘗試 HELO 并屏蔽 ESMTP 選項。

如果郵件被至少一個(gè)接收方接受則此方法將正常返回。 在其他情況下它將引發(fā)異常。 也就是說(shuō),如果此方法沒(méi)有引發(fā)異常,則應當會(huì )有人收到你的郵件。 如果此方法沒(méi)有引發(fā)異常,它將返回一個(gè)字典,其中的條目對應每個(gè)拒絕的接收方。 每個(gè)條目均包含由服務(wù)器發(fā)送的 SMTP 錯誤代碼和相應錯誤消息所組成的元組。

如果 SMTPUTF8 包括在 mail_options 中,并且被服務(wù)器所支持,則 from_addrto_addrs 可能包含非 ASCII 字符。

此方法可能引發(fā)以下異常:

SMTPRecipientsRefused

所有收件人都被拒絕。 無(wú)人收到郵件。 該異常的 recipients 屬性是一個(gè)字典,其中有被拒絕收件人的信息(類(lèi)似于至少有一個(gè)收件人接受郵件時(shí)所返回的信息)。

SMTPHeloError

服務(wù)器沒(méi)有正確回復 HELO 問(wèn)候。

SMTPSenderRefused

服務(wù)器不接受 from_addr。

SMTPDataError

服務(wù)器回復了一個(gè)意外的錯誤代碼(而不是拒絕收件人)。

SMTPNotSupportedError

mail_options 中給出了 SMTPUTF8 但是不被服務(wù)器所支持。

除非另有說(shuō)明,即使在引發(fā)異常之后連接仍將被打開(kāi)。

在 3.2 版更改: msg 可以為字節串。

在 3.5 版更改: 增加了 SMTPUTF8 支持,并且如果指定了 SMTPUTF8 但是不被服務(wù)器所支持則可能會(huì )引發(fā) SMTPNotSupportedError。

SMTP.send_message(msg, from_addr=None, to_addrs=None, mail_options=(), rcpt_options=())?

本方法是一種快捷方法,用于帶著(zhù)消息調用 sendmail(),消息由 email.message.Message 對象表示。參數的含義與 sendmail() 中的相同,除了 msg,它是一個(gè) Message 對象。

如果 from_addrNoneto_addrsNone,那么``send_message``將根據 RFC 5322,從 msg 頭部提取地址填充下列參數:如果頭部存在 Sender 字段,則用它填充 from_addr,不存在則用 From 字段填充 from_addr。to_addrs 組合了 msg 中的 To, CcBcc 字段的值(字段存在的情況下)。如果一組 Resent-* 頭部恰好出現在 message 中,那么就忽略常規的頭部,改用 Resent-* 頭部。如果 message 包含多組 Resent-* 頭部,則引發(fā) ValueError,因為無(wú)法明確檢測出哪一組 Resent- 頭部是最新的。

send_message 使用 BytesGenerator 來(lái)序列化 msg,且將 \r\n 作為 linesep,并調用 sendmail() 來(lái)傳輸序列化后的結果。無(wú)論 from_addrto_addrs 的值為何,send_message 都不會(huì )傳輸 msg 中可能出現的 BccResent-Bcc 頭部。如果 from_addrto_addrs 中的某個(gè)地址包含非 ASCII 字符,且服務(wù)器沒(méi)有聲明支持 SMTPUTF8,則引發(fā) SMTPNotSupported 錯誤。如果服務(wù)器支持,則 Message 將按新克隆的 policy 進(jìn)行序列化,其中的 utf8 屬性被設置為 True,且 SMTPUTF8BODY=8BITMIME 被添加到 mail_options 中。

3.2 新版功能.

3.5 新版功能: 支持國際化地址 (SMTPUTF8)。

SMTP.quit()?

終結 SMTP 會(huì )話(huà)并關(guān)閉連接。 返回 SMTP QUIT 命令的結果。

與標準 SMTP/ESMTP 命令 HELP, RSET, NOOP, MAIL, RCPTDATA 對應的低層級方法也是受支持的。 通常不需要直接調用這些方法,因此它們沒(méi)有被寫(xiě)入本文檔。 相關(guān)細節請參看模塊代碼。

SMTP 示例?

這個(gè)例子提示用戶(hù)輸入消息封包所需的地址 ('To' 和 'From' 地址),以及所要封包的消息。 請注意包括在消息中的標頭必須包括在輸入的消息中;這個(gè)例子不對 RFC 822 標頭進(jìn)行任何處理。 特別地,'To' 和 'From' 地址必須顯式地包括在消息標頭中。

import smtplib

def prompt(prompt):
    return input(prompt).strip()

fromaddr = prompt("From: ")
toaddrs  = prompt("To: ").split()
print("Enter message, end with ^D (Unix) or ^Z (Windows):")

# Add the From: and To: headers at the start!
msg = ("From: %s\r\nTo: %s\r\n\r\n"
       % (fromaddr, ", ".join(toaddrs)))
while True:
    try:
        line = input()
    except EOFError:
        break
    if not line:
        break
    msg = msg + line

print("Message length is", len(msg))

server = smtplib.SMTP('localhost')
server.set_debuglevel(1)
server.sendmail(fromaddr, toaddrs, msg)
server.quit()

備注

通常,你將需要使用 email 包的特性來(lái)構造電子郵件消息,然后你可以通過(guò) send_message() 來(lái)發(fā)送它,參見(jiàn) email: 示例。