smtplib
--- SMTP 協(xié)議客戶端?
源代碼: Lib/smtplib.py
smtplib
模塊定義了一個 SMTP 客戶端會話對象,該對象可將郵件發(fā)送到互聯(lián)網上任何帶有 SMTP 或 ESMTP 監(jiān)聽程序的計算機。 關于 SMTP 和 ESMTP 操作的更多細節(jié)請參閱 RFC 821 (簡單郵件傳輸協(xié)議) 和 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()
調用返回了表示成功的代碼以外的信息,則會引發(fā)SMTPConnectError
。 可選的 timeout 形參指定了阻塞操作如連接嘗試的超時秒數(shù)(如果未指定,則將使用全局默認超時設置)。 如果達到超時限制,則會引發(fā)TimeoutError
。 可選的 source_address 形參允許在在有多張網卡的計算機中綁定到某些特定的源地址,和/或綁定到某些特定的源 TCP 端口。 它接受一個 2 元組 (host, port) 作為在連接之前所綁定作為其源地址的套接字。 如果省略(或者如果 host 或 port 為''
和/或分別為 0)則將使用 OS 的默認行為。正常使用時,只需要初始化或 connect 方法,
sendmail()
方法,再加上SMTP.quit()
方法即可。下文包括了一個示例。SMTP
類支持with
語句。當這樣使用時,with
語句一退出就會自動發(fā)出 SMTPQUIT
命令。例如:>>> from smtplib import SMTP >>> with SMTP("domain.org") as smtp: ... smtp.noop() ... (250, b'Ok') >>>
引發(fā)一個 審計事件
smtplib.send
,附帶參數(shù)self
,data
。在 3.3 版更改: 添加了對
with
語句的支持。在 3.3 版更改: 添加了 source_address 參數(shù)。
3.5 新版功能: 現(xiàn)在已支持 SMTPUTF8 擴展 (RFC 6531)。
在 3.9 版更改: 如果 timeout 形參被設為零,則它將引發(fā)
ValueError
來阻止創(chuàng)建非阻塞的套接字
- 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)??蛇x參數(shù) local_hostname、timeout 和 source_address 的含義與SMTP
類中的相同。可選參數(shù) context 是一個SSLContext
對象,可以從多個方面配置安全連接。請閱讀 安全考量 以獲取最佳實踐。keyfile 和 certfile 是 context 的傳統(tǒng)替代物,它們可以指向 PEM 格式的私鑰和證書鏈文件用于 SSL 連接。
在 3.3 版更改: 增加了 context。
在 3.3 版更改: 添加了 source_address 參數(shù)。
在 3.4 版更改: 本類現(xiàn)在支持使用
ssl.SSLContext.check_hostname
和 服務器名稱指示 (參閱ssl.HAS_SNI
)進行主機名檢查。3.6 版后已移除: keyfile 和 certfile 已棄用并轉而推薦 context。 請改用
ssl.SSLContext.load_cert_chain()
或讓ssl.create_default_context()
為你選擇系統(tǒng)所信任的 CA 證書。在 3.9 版更改: 如果 timeout 形參被設為零,則它將引發(fā)
ValueError
來阻止創(chuàng)建非阻塞的套接字
- class smtplib.LMTP(host='', port=LMTP_PORT, local_hostname=None, source_address=None[, timeout])?
LMTP 協(xié)議與 ESMTP 非常相似,它很大程度上基于標準的 SMTP 客戶端。將 Unix 套接字用于 LMTP 是很常見的,因此
connect()
方法支持 Unix 套接字,也支持常規(guī)的 host:port 服務器??蛇x參數(shù) local_hostname 和 source_address 的含義與SMTP
類中的相同。要指定 Unix 套接字,host 必須使用絕對路徑,以 '/' 開頭。支持使用常規(guī)的 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?
發(fā)送方地址被拒絕。 除了在所有
SMTPResponseException
異常上設置的屬性,還會將 'sender' 設為代表拒絕方 SMTP 服務器的字符串。
- exception smtplib.SMTPRecipientsRefused?
所有接收方地址被拒絕。 每個接收方的錯誤可通過屬性
recipients
來訪問,該屬性是一個字典,其元素順序與SMTP.sendmail()
所返回的一致。
- exception smtplib.SMTPDataError?
SMTP 服務器拒絕接收消息數(shù)據(jù)。
- exception smtplib.SMTPConnectError?
在建立與服務器的連接期間發(fā)生了錯誤。
- exception smtplib.SMTPHeloError?
服務器拒絕了我們的
HELO
消息。
- exception smtplib.SMTPNotSupportedError?
嘗試的命令或選項不被服務器所支持。
3.5 新版功能.
- exception smtplib.SMTPAuthenticationError?
SMTP 認證出現(xiàn)問題。 最大的可能是服務器不接受所提供的用戶名/密碼組合。
參見
SMTP 對象?
一個 SMTP
實例擁有以下方法:
- SMTP.set_debuglevel(level)?
設置調試輸出級別。 如果 level 的值為 1 或
True
,就會產生連接的調試信息,以及所有發(fā)送和接收服務器的信息。 如果 level 的值為 2 ,則這些信息會被加上時間戳。在 3.5 版更改: 添調試級別 2 。
- SMTP.docmd(cmd, args='')?
向服務器發(fā)送一條命令 cmd 。 可選的參數(shù) args 被簡單地串聯(lián)到命令中,用一個空格隔開。
這將返回一個由數(shù)字響應代碼和實際響應行組成的2元組(多行響應被連接成一個長行)。
在正常操作中,應該沒有必要明確地調用這個方法。它被用來實現(xiàn)其他方法,對于測試私有擴展可能很有用。
如果在等待回復的過程中,與服務器的連接丟失,
SMTPServerDisconnected
將被觸發(fā)。
- SMTP.connect(host='localhost', port=0)?
連接到某個主機的某個端口。默認是連接到 localhost 的標準 SMTP 端口(25)上。如果主機名以冒號 (
':'
) 結尾,后跟數(shù)字,則該后綴將被刪除,且數(shù)字將視作要使用的端口號。如果在實例化時指定了 host,則構造函數(shù)會自動調用本方法。返回包含響應碼和響應消息的 2 元組,它們由服務器在其連接響應中發(fā)送。觸發(fā)一個 auditing event
smtplib.connect
,其參數(shù)為self
,host
,port
。
- SMTP.helo(name='')?
使用
HELO
向 SMTP 服務器表明自己的身份。 hostname 參數(shù)默認為本地主機的完全合格域名。服務器返回的消息被存儲為對象的helo_resp
屬性。在正常操作中,應該沒有必要明確調用這個方法。它將在必要時被
sendmail()
隱式調用。
- SMTP.ehlo(name='')?
使用
EHLO
向 ESMTP 服務器表明自己的身份。 hostname 參數(shù)默認為本地主機的完全合格域名。 檢查 ESMTP 選項的響應,并存儲它們供has_extn()
使用。同時設置幾個信息屬性:服務器返回的消息被存儲為ehlo_resp
屬性,does_esmtp
根據(jù)服務器是否支持 ESMTP 被設置為True
或False
,而esmtp_features
將是一個字典,包含這個服務器支持的 SMTP 服務擴展的名稱,以及它們的參數(shù)(如果有)。除非你想在發(fā)送郵件前使用
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 服務器。 參數(shù)是用于認證的用戶名和密碼。 如果會話在之前沒有執(zhí)行過
EHLO
或HELO
命令,此方法會先嘗試 ESMTPEHLO
。 如果認證成功則此方法將正常返回,否則可能引發(fā)以下異常:SMTPHeloError
服務器沒有正確回復
HELO
問候。SMTPAuthenticationError
服務器不接受所提供的用戶名/密碼組合。
SMTPNotSupportedError
服務器不支持
AUTH
命令。SMTPException
未找到適當?shù)恼J證方法。
smtplib
所支持的每種認證方法只要被服務器聲明支持就會被依次嘗試。 請參閱auth()
獲取受支持的認證方法列表。 initial_response_ok 會被傳遞給auth()
。可選的關鍵字參數(shù) initial_response_ok 對于支持它的認證方法,是否可以與
AUTH
命令一起發(fā)送 RFC 4954 中所規(guī)定的“初始響應”,而不是要求回復/響應。在 3.5 版更改: 可能會引發(fā)
SMTPNotSupportedError
,并添加 initial_response_ok 形參。
- SMTP.auth(mechanism, authobject, *, initial_response_ok=True)?
為指定的認證機制 mechanism 發(fā)送
SMTP
AUTH
命令,并通過 authobject 處理回復響應。mechanism 指定要使用何種認證機制作為
AUTH
命令的參數(shù);可用的值是在esmtp_features
的auth
元素中列出的內容。authobject 必須是接受一個可選的單獨參數(shù)的可調用對象:
data = authobject(challenge=None)
如果可選的關鍵字參數(shù) initial_response_ok 為真值,則將先不帶參數(shù)地調用
authobject()
。 它可以返回 RFC 4954 "初始響應" ASCIIstr
,其內容將被編碼并使用下述的AUTH
命令來發(fā)送。 如果authobject()
不支持初始響應(例如由于要求一個回復),它應當將None
作為附帶challenge=None
調用的返回值。 如果 initial_response_ok 為假值,則authobject()
將不會附帶None
被首先調用。如果初始響應檢測返回了
None
,或者如果 initial_response_ok 為假值,則將調用authobject()
來處理服務器的回復響應;它所傳遞的 challenge 參數(shù)將為一個bytes
。 它應當返回用 base64 進行編碼的 ASCIIstr
data 并發(fā)送給服務器。SMTP
類提供的authobjects
針對CRAM-MD5
,PLAIN
和LOGIN
等機制;它們的名稱分別是SMTP.auth_cram_md5
,SMTP.auth_plain
和SMTP.auth_login
。 它們都要求將user
和password
這兩個SMTP
實例屬性設為適當?shù)闹怠?/p>用戶代碼通常不需要直接調用
auth
,而是調用login()
方法,它將按上述順序依次嘗試上述每一種機制。auth
被公開以便輔助實現(xiàn)smtplib
沒有(或尚未)直接支持的認證方法。3.5 新版功能.
- SMTP.starttls(keyfile=None, certfile=None, context=None)?
將 SMTP 連接設為 TLS (傳輸層安全) 模式。 后續(xù)的所有 SMTP 命令都將被加密。 你應當隨即再次調用
ehlo()
。如果提供了 keyfile 和 certfile,它們會被用來創(chuàng)建
ssl.SSLContext
。可選的 context 形參是一個
ssl.SSLContext
對象;它是使用密鑰文件和證書的替代方式,如果指定了該形參則 keyfile 和 certfile 都應為None
。如果這個會話中沒有先前的
EHLO
orHELO
命令,該方法會首先嘗試 ESMTPEHLO
。3.6 版后已移除: keyfile 和 certfile 已棄用并轉而推薦 context。 請改用
ssl.SSLContext.load_cert_chain()
或讓ssl.create_default_context()
為你選擇系統(tǒng)所信任的 CA 證書。SMTPHeloError
服務器沒有正確回復
HELO
問候。SMTPNotSupportedError
服務器不支持 STARTTLS 擴展。
RuntimeError
SSL/TLS 支持在你的 Python 解釋器上不可用。
在 3.3 版更改: 增加了 context。
在 3.4 版更改: 此方法現(xiàn)在支持使用
SSLContext.check_hostname
和 服務器名稱指示符 (參見HAS_SNI
) 進行主機名檢查。在 3.5 版更改: 因缺少 STARTTLS 支持而引發(fā)的錯誤現(xiàn)在是
SMTPNotSupportedError
子類而不是SMTPException
基類。
- SMTP.sendmail(from_addr, to_addrs, msg, mail_options=(), rcpt_options=())?
發(fā)送郵件。必要參數(shù)是一個 RFC 822 發(fā)件地址字符串,一個 RFC 822 收件地址字符串列表(裸字符串將被視為含有 1 個地址的列表),以及一個消息字符串。調用者可以將 ESMTP 選項列表(如
8bitmime
)作為 mail_options 傳入,用于MAIL FROM
命令。需要與所有RCPT
命令一起使用的 ESMTP 選項(如DSN
命令)可以作為 rcpt_options 傳入。(如果需要對不同的收件人使用不同的 ESMTP 選項,則必須使用底層的方法來發(fā)送消息,如mail()
,rcpt()
和data()
。)備注
from_addr 和 to_addrs 形參被用來構造傳輸代理所使用的消息封包。
sendmail
不會以任何方式修改消息標頭。msg 可以是一個包含 ASCII 范圍內字符的字符串,或是一個字節(jié)串。 字符串會使用 ascii 編解碼器編碼為字節(jié)串,并且單獨的
\r
和\n
字符會被轉換為\r\n
字符序列。 字節(jié)串則不會被修改。如果在此之前本會話沒有執(zhí)行過
EHLO
或HELO
命令,此方法會先嘗試 ESMTPEHLO
。 如果服務器執(zhí)行了 ESMTP,消息大小和每個指定的選項將被傳遞給它(如果指定的選項屬于服務器聲明的特性集)。 如果EHLO
失敗,則將嘗試HELO
并屏蔽 ESMTP 選項。如果郵件被至少一個接收方接受則此方法將正常返回。 在其他情況下它將引發(fā)異常。 也就是說,如果此方法沒有引發(fā)異常,則應當會有人收到你的郵件。 如果此方法沒有引發(fā)異常,它將返回一個字典,其中的條目對應每個拒絕的接收方。 每個條目均包含由服務器發(fā)送的 SMTP 錯誤代碼和相應錯誤消息所組成的元組。
如果
SMTPUTF8
包括在 mail_options 中,并且被服務器所支持,則 from_addr 和 to_addrs 可能包含非 ASCII 字符。此方法可能引發(fā)以下異常:
SMTPRecipientsRefused
所有收件人都被拒絕。 無人收到郵件。 該異常的
recipients
屬性是一個字典,其中有被拒絕收件人的信息(類似于至少有一個收件人接受郵件時所返回的信息)。SMTPHeloError
服務器沒有正確回復
HELO
問候。SMTPSenderRefused
服務器不接受 from_addr。
SMTPDataError
服務器回復了一個意外的錯誤代碼(而不是拒絕收件人)。
SMTPNotSupportedError
在 mail_options 中給出了
SMTPUTF8
但是不被服務器所支持。
除非另有說明,即使在引發(fā)異常之后連接仍將被打開。
在 3.2 版更改: msg 可以為字節(jié)串。
在 3.5 版更改: 增加了
SMTPUTF8
支持,并且如果指定了SMTPUTF8
但是不被服務器所支持則可能會引發(fā)SMTPNotSupportedError
。
- SMTP.send_message(msg, from_addr=None, to_addrs=None, mail_options=(), rcpt_options=())?
本方法是一種快捷方法,用于帶著消息調用
sendmail()
,消息由email.message.Message
對象表示。參數(shù)的含義與sendmail()
中的相同,除了 msg,它是一個Message
對象。如果 from_addr 為
None
或 to_addrs 為None
,那么``send_message``將根據(jù) RFC 5322,從 msg 頭部提取地址填充下列參數(shù):如果頭部存在 Sender 字段,則用它填充 from_addr,不存在則用 From 字段填充 from_addr。to_addrs 組合了 msg 中的 To, Cc 和 Bcc 字段的值(字段存在的情況下)。如果一組 Resent-* 頭部恰好出現(xiàn)在 message 中,那么就忽略常規(guī)的頭部,改用 Resent-* 頭部。如果 message 包含多組 Resent-* 頭部,則引發(fā)ValueError
,因為無法明確檢測出哪一組 Resent- 頭部是最新的。send_message
使用BytesGenerator
來序列化 msg,且將\r\n
作為 linesep,并調用sendmail()
來傳輸序列化后的結果。無論 from_addr 和 to_addrs 的值為何,send_message
都不會傳輸 msg 中可能出現(xiàn)的 Bcc 或 Resent-Bcc 頭部。如果 from_addr 和 to_addrs 中的某個地址包含非 ASCII 字符,且服務器沒有聲明支持SMTPUTF8
,則引發(fā)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
對應的低層級方法也是受支持的。 通常不需要直接調用這些方法,因此它們沒有被寫入本文檔。 相關細節(jié)請參看模塊代碼。
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()
來發(fā)送它,參見 email: 示例。