smtplib ---SMTP協議客戶端?
源代碼: Lib/smtplib.py
smtplib 模塊定義了一個 SMTP 客戶端會話對象,該對象可將郵件發送到 Internet 上帶有 SMTP 或 ESMTP 接收程序的計算機。 關于 SMTP 和 ESMTP 操作的詳情請參閱 RFC 821 (簡單郵件傳輸協議) 和 RFC 1869 (SMTP 服務擴展)。
-
class
smtplib.SMTP(host='', port=0, local_hostname=None, [timeout, ]source_address=None)? 一個
SMTP實例就是一個封裝好的 SMTP 連接。該實例具有的方法支持所有 SMTP 和 ESMTP 操作。如果傳入了可選參數 host 和 port,那么將在初始化時使用這些參數調用 SMTPconnect()方法。如果傳入了 local_hostname,它將在 HELO/EHLO 命令中被用作本地主機的 FQDN。否則將使用socket.getfqdn()找到本地主機名。如果connect()返回了成功碼以外的內容,則引發SMTPConnectError異常。可選參數 timeout 指定阻塞操作(如連接嘗試)的超時(以秒為單位,如果未指定超時,將使用全局默認超時設置)。到達超時時長后會引發socket.timeout異常。可選參數 source_address 允許在有多張網卡的計算機中綁定到某些特定的源地址,和/或綁定到某些特定的源 TCP 端口。在連接前,套接字需要綁定一個 2 元組 (host, port) 作為其源地址。如果省略,或者是主機為''和/或端口為 0,則將使用操作系統默認行為。正常使用時,只需要初始化或 connect 方法,
sendmail()方法,再加上SMTP.quit()方法即可。下文包括了一個示例。SMTP類支持with語句。當這樣使用時,with語句一退出就會自動發出 SMTPQUIT命令。例如:>>> from smtplib import SMTP >>> with SMTP("domain.org") as smtp: ... smtp.noop() ... (250, b'Ok') >>>
在 3.3 版更改: 支持了
with語句。在 3.3 版更改: 添加了 source_address 參數。
3.5 新版功能: 現在已支持 SMTPUTF8 擴展 (RFC 6531)。
-
class
smtplib.SMTP_SSL(host='', port=0, local_hostname=None, keyfile=None, certfile=None, [timeout, ]context=None, source_address=None)? SMTP_SSL實例與SMTP實例的行為完全相同。在開始連接就需要 SSL,且starttls()不適合的情況下,應該使用SMTP_SSL。如果未指定 host,則使用 localhost。如果 port 為 0,則使用標準 SMTP-over-SSL 端口(465)。可選參數 local_hostname、timeout 和 source_address 的含義與SMTP類中的相同。可選參數 context 是一個SSLContext對象,可以從多個方面配置安全連接。請閱讀 安全考量 以獲取最佳實踐。keyfile 和 certfile 是 context 的傳統替代物,它們可以指向 PEM 格式的私鑰和證書鏈文件用于 SSL 連接。
在 3.3 版更改: 增加了 context。
在 3.3 版更改: 添加了 source_address 參數。
在 3.4 版更改: 本類現在支持通過
ssl.SSLContext.check_hostname和 服務器名稱提示 (參閱ssl.HAS_SNI)進行主機名檢查。3.6 版后已移除: keyfile 和 certfile 已棄用并轉而推薦 context。 請改用
ssl.SSLContext.load_cert_chain()或讓ssl.create_default_context()為你選擇系統所信任的 CA 證書。
-
class
smtplib.LMTP(host='', port=LMTP_PORT, local_hostname=None, source_address=None)? LMTP 協議與 ESMTP 非常相似,它很大程度上基于標準的 SMTP 客戶端。將 Unix 套接字用于 LMTP 是很常見的,因此
connect()方法支持 Unix 套接字,也支持常規的 host:port 服務器。可選參數 local_hostname 和 source_address 的含義與SMTP類中的相同。要指定 Unix 套接字,host 必須使用絕對路徑,以 '/' 開頭。支持使用常規的 SMTP 機制來進行認證。 當使用 Unix 套接字時,LMTP 通常不支持或要求任何認證,但你的情況可能會有所不同。
同樣地定義了一組精心選擇的異常:
-
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,就會產生連接的調試信息,以及所有發送和接收服務器的信息。 如果 level 的值為 2 ,則這些信息會被加上時間戳。在 3.5 版更改: 添調試級別 2 。
-
SMTP.docmd(cmd, args='')? 向服務器發送一條命令 cmd 。 可選的參數 args 被簡單地串聯到命令中,用一個空格隔開。
這將返回一個由數字響應代碼和實際響應行組成的2元組(多行響應被連接成一個長行)。
在正常操作中,應該沒有必要明確地調用這個方法。它被用來實現其他方法,對于測試私有擴展可能很有用。
如果在等待回復的過程中,與服務器的連接丟失,
SMTPServerDisconnected將被觸發。
-
SMTP.connect(host='localhost', port=0)? 連接到某個主機的某個端口。默認是連接到 localhost 的標準 SMTP 端口(25)上。如果主機名以冒號 (
':') 結尾,后跟數字,則該后綴將被刪除,且數字將視作要使用的端口號。如果在實例化時指定了 host,則構造函數會自動調用本方法。返回包含響應碼和響應消息的 2 元組,它們由服務器在其連接響應中發送。
-
SMTP.helo(name='')? 使用
HELO向 SMTP 服務器表明自己的身份。 hostname 參數默認為本地主機的完全合格域名。服務器返回的消息被存儲為對象的helo_resp屬性。在正常操作中,應該沒有必要明確調用這個方法。它將在必要時被
sendmail()隱式調用。
-
SMTP.ehlo(name='')? 使用
EHLO向 ESMTP 服務器標識自身。hostname 參數默認為 localhost 的標準域名。使用has_extn()來檢查響應中的 ESMTP 選項,并將它們保存起來。還給一些信息性的屬性賦值:服務器返回的消息存儲為ehlo_resp屬性;根據服務器是否支持 ESMTP,將does_esmtp設置為 true 或 false;而esmtp_features是一個字典,包含該服務器支持的 SMTP 服務擴展的名稱及參數(如果有參數)。除非你想在發送郵件前使用
has_extn(),否則應該沒有必要明確調用這個方法。 它將在必要時被sendmail()隱式調用。
-
SMTP.ehlo_or_helo_if_needed()? 如果這個會話中沒有先前的
EHLO或HELO命令,該方法會調用ehlo()和/或helo()。它首先嘗試 ESMTPEHLO。SMTPHeloError服務器沒有正確回復
HELO問候。
-
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 對于支持它的認證方法,是否可以與
AUTH命令一起發送 RFC 4954 中所規定的“初始響應”,而不是要求回復/響應。在 3.5 版更改: 可能會引發
SMTPNotSupportedError,并添加 initial_response_ok 形參。
-
SMTP.auth(mechanism, authobject, *, initial_response_ok=True)? 為指定的認證機制 mechanism 發送
SMTPAUTH命令,并通過 authobject 處理回復響應。mechanism 指定要使用何種認證機制作為
AUTH命令的參數;可用的值是在esmtp_features的auth元素中列出的內容。authobject 必須是接受一個可選的單獨參數的可調用對象:
data = authobject(challenge=None)
如果可選的關鍵字參數 initial_response_ok 為真值,則將先不帶參數地調用
authobject()。 它可以返回 RFC 4954 "初始響應" ASCIIstr,其內容將被編碼并使用下述的AUTH命令來發送。 如果authobject()不支持初始響應(例如由于要求一個回復),它應當將None作為附帶challenge=None調用的返回值。 如果 initial_response_ok 為假值,則authobject()將不會附帶None被首先調用。如果初始響應檢測返回了
None,或者如果 initial_response_ok 為假值,則將調用authobject()來處理服務器的回復響應;它所傳遞的 challenge 參數將為一個bytes。 它應當返回用 base64 進行編碼的 ASCIIstrdata 并發送給服務器。SMTP類提供的authobjects針對CRAM-MD5,PLAIN和LOGIN等機制;它們的名稱分別是SMTP.auth_cram_md5,SMTP.auth_plain和SMTP.auth_login。 它們都要求將user和password這兩個SMTP實例屬性設為適當的值。用戶代碼通常不需要直接調用
auth,而是調用login()方法,它將按上述順序依次嘗試上述每一種機制。auth被公開以便輔助實現smtplib沒有(或尚未)直接支持的認證方法。3.5 新版功能.
-
SMTP.starttls(keyfile=None, certfile=None, context=None)? 將 SMTP 連接設為 TLS (傳輸層安全) 模式。 后續的所有 SMTP 命令都將被加密。 你應當隨即再次調用
ehlo()。如果提供了 keyfile 和 certfile,它們會被用來創建
ssl.SSLContext。可選的 context 形參是一個
ssl.SSLContext對象;它是使用密鑰文件和證書的替代方式,如果指定了該形參則 keyfile 和 certfile 都應為None。如果這個會話中沒有先前的
EHLOorHELO命令,該方法會首先嘗試 ESMTPEHLO。3.6 版后已移除: keyfile 和 certfile 已棄用并轉而推薦 context。 請改用
ssl.SSLContext.load_cert_chain()或讓ssl.create_default_context()為你選擇系統所信任的 CA 證書。SMTPHeloError服務器沒有正確回復
HELO問候。SMTPNotSupportedError服務器不支持 STARTTLS 擴展。
RuntimeErrorSSL/TLS 支持在你的 Python 解釋器上不可用。
在 3.3 版更改: 增加了 context。
在 3.4 版更改: 此方法現在支持使用
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 個地址的列表),以及一個消息字符串。調用者可以將 ESMTP 選項列表(如
8bitmime)作為 mail_options 傳入,用于MAIL FROM命令。需要與所有RCPT命令一起使用的 ESMTP 選項(如DSN命令)可以作為 rcpt_options 傳入。(如果需要對不同的收件人使用不同的 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所有收件人都被拒絕。 無人收到郵件。 該異常的
recipients屬性是一個字典,其中有被拒絕收件人的信息(類似于至少有一個收件人接受郵件時所返回的信息)。SMTPHeloError服務器沒有正確回復
HELO問候。SMTPSenderRefused服務器不接受 from_addr。
SMTPDataError服務器回復了一個意外的錯誤代碼(而不是拒絕收件人)。
SMTPNotSupportedError在 mail_options 中給出了
SMTPUTF8但是不被服務器所支持。
除非另有說明,即使在引發異常之后連接仍將被打開。
在 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 頭部提取地址填充下列參數:如果頭部存在 Sender 字段,則用它填充 from_addr,不存在則用 From 字段填充 from_addr。to_addrs 組合了 msg 中的 To, Cc 和 Bcc 字段的值(字段存在的情況下)。如果一組 Resent-* 頭部恰好出現在 message 中,那么就忽略常規的頭部,改用 Resent-* 頭部。如果 message 包含多組 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,則引發SMTPNotSupported錯誤。如果服務器支持,則Message將按新克隆的policy進行序列化,其中的utf8屬性被設置為True,且SMTPUTF8和BODY=8BITMIME被添加到 mail_options 中。3.2 新版功能.
3.5 新版功能: 支持國際化地址 (
SMTPUTF8)。
-
SMTP.quit()? 終結 SMTP 會話并關閉連接。 返回 SMTP
QUIT命令的結果。
與標準 SMTP/ESMTP 命令 HELP, RSET, NOOP, MAIL, RCPT 和 DATA 對應的低層級方法也是受支持的。 通常不需要直接調用這些方法,因此它們沒有被寫入本文檔。 相關細節請參看模塊代碼。
SMTP 示例?
這個例子提示用戶輸入消息封包所需的地址 ('To' 和 'From' 地址),以及所要封包的消息。 請注意包括在消息中的標頭必須包括在輸入的消息中;這個例子不對 RFC 822 標頭進行任何處理。 特別地,'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 包的特性來構造電子郵件消息,然后你可以通過 send_message() 來發送它,參見 email: 示例。
