smtplib --- SMTP 協定用戶端¶
原始碼:Lib/smtplib.py
smtplib 模組定義了一個 SMTP 用戶端 session 物件,可用於將郵件傳送至任何具備 SMTP 或 ESMTP listener daemon 的網際網路機器。有關 SMTP 和 ESMTP 運作的細節,請參閱 RFC 821(Simple Mail Transfer Protocol,簡易郵件傳輸協定)和 RFC 1869(SMTP Service Extensions,SMTP 服務擴充)。
可用性: not WASI.
此模組在 WebAssembly 平台上不起作用或無法使用。更多資訊請參閱 WebAssembly 平台。
- class smtplib.SMTP(host='', port=0, local_hostname=None, [timeout, ]source_address=None)¶
SMTP實例封裝了一個 SMTP 連線。它擁有支援完整 SMTP 和 ESMTP 操作的各種方法。如果有給定選用的 host 和 port 參數,初始化期間會以這些參數呼叫 SMTP 的connect()方法。如果有指定 local_hostname,則會將其用作 HELO/EHLO 指令中本地主機的 FQDN。否則,會使用socket.getfqdn()來尋找本地主機名稱。如果connect()呼叫回傳的不是成功碼,則會引發SMTPConnectError。選用的 timeout 參數會以秒為單位指定阻塞操作(例如連線嘗試)的逾時時間(如果未指定,則會使用全域預設的逾時設定)。如果逾時,則會引發TimeoutError。選用的 source_address 參數允許在具有多個網路介面的機器中綁定到某個特定的來源位址,和/或綁定到某個特定的來源 TCP 連接埠。它接受一個 2-tuple(host, port),供 socket 在連線前綁定為其來源位址。如果省略(或者 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') >>>
所有指令都會引發一個附帶引數
self、data的稽核事件smtplib.SMTP.send,其中data為即將傳送至遠端的位元組。在 3.3 版的變更: 新增對
with陳述式的支援。在 3.3 版的變更: 新增 source_address 引數。
在 3.5 版被加入: 現在支援 SMTPUTF8 擴充(RFC 6531)。
在 3.9 版的變更: 如果 timeout 參數被設為零,則會引發
ValueError,以防止建立非阻塞的 socket。
- class smtplib.SMTP_SSL(host='', port=0, local_hostname=None, *, [timeout, ]context=None, source_address=None)¶
SMTP_SSL實例的行為與SMTP的實例完全相同。SMTP_SSL應該用於從連線一開始就需要 SSL、且不適合使用starttls()的情況。如果未指定 host,則會使用本地主機。如果 port 為零,則會使用標準的 SMTP-over-SSL 連接埠(465)。選用引數 local_hostname、timeout 和 source_address 的意義與它們在SMTP類別中的相同。同樣為選用的 context 可以包含一個SSLContext,並允許設定安全連線的各個面向。最佳做法請參閱 Security considerations。在 3.3 版的變更: 新增 context。
在 3.3 版的變更: 新增 source_address 引數。
在 3.4 版的變更: 此類別現在支援以
ssl.SSLContext.check_hostname進行主機名稱檢查以及 伺服器名稱指示 (Server Name Indication)(請參閱ssl.HAS_SNI)。在 3.9 版的變更: 如果 timeout 參數被設為零,則會引發
ValueError,以防止建立非阻塞的 socket在 3.12 版的變更: 已棄用的 keyfile 和 certfile 參數已被移除。
- class smtplib.LMTP(host='', port=LMTP_PORT, local_hostname=None, source_address=None[, timeout])¶
LMTP 協定與 ESMTP 非常相似,它大量基於標準的 SMTP 用戶端。LMTP 常會使用 Unix socket,因此我們的
connect()方法除了支援一般的 host:port 伺服器外,也必須支援它。選用引數 local_hostname 和 source_address 的意義與它們在SMTP類別中的相同。要指定一個 Unix socket,你必須為 host 使用以 '/' 開頭的絕對路徑。支援使用一般的 SMTP 機制進行身分驗證。當使用 Unix socket 時,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¶
一個 dictionary,其類型與
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 版的變更: 新增 debuglevel 2。
- SMTP.docmd(cmd, args='')¶
傳送一個指令 cmd 給伺服器。選用引數 args 只會以一個空格分隔串接到指令後。
這會回傳一個 2-tuple,由數值回應碼和實際的回應行所組成(多行回應會被合併為一長行)。
在正常操作中,應該不需要明確地呼叫此方法。它被用於實作其他方法,並可能對測試私有擴充很有用。
如果在等待回覆時與伺服器的連線中斷,則會引發
SMTPServerDisconnected。
- SMTP.connect(host='localhost', port=0)¶
在給定的連接埠上連線到某個主機。預設值是連線到本地主機的標準 SMTP 連接埠(25)。如果主機名稱以一個冒號(
':')後接一個數字結尾,該後綴會被去除,並將該數字解釋為要使用的連接埠號。如果在實例化期間有指定主機,建構函式會自動叫用此方法。回傳一個 2-tuple,內容為伺服器在其連線回應中所傳送的回應碼和訊息。引發一個附帶引數
self、host、port的稽核事件smtplib.connect。
- SMTP.helo(name='')¶
使用
HELO向 SMTP 伺服器表明你的身分。hostname 引數預設為本地主機的完整網域名稱(fully qualified domain name)。伺服器回傳的訊息會被儲存為物件的helo_resp屬性。在正常操作中,應該不需要明確地呼叫此方法。必要時它會被
sendmail()隱式地呼叫。
- SMTP.ehlo(name='')¶
使用
EHLO向 ESMTP 伺服器表明你的身分。hostname 引數預設為本地主機的完整網域名稱(fully qualified domain name)。檢視回應中的 ESMTP 選項並將其儲存起來,供has_extn()使用。同時也會設定數個資訊性屬性:伺服器回傳的訊息會被儲存為ehlo_resp屬性,does_esmtp會依伺服器是否支援 ESMTP 被設為True或False,而esmtp_features會是一個 dictionary,包含此伺服器所支援的 SMTP 服務擴充名稱以及它們的參數(如果有的話)。除非你想在寄送郵件前使用
has_extn(),否則應該不需要明確地呼叫此方法。必要時它會被sendmail()隱式地呼叫。
- SMTP.ehlo_or_helo_if_needed()¶
如果此 session 之前沒有過
EHLO或HELO指令,此方法會呼叫ehlo()和/或helo()。它會先嘗試 ESMTP 的EHLO。SMTPHeloError伺服器沒有正確地回覆
HELO問候。
- SMTP.verify(address)¶
使用 SMTP 的
VRFY檢查某個位址在此伺服器上的有效性。如果使用者位址有效,則回傳一個由代號 250 和一個完整的 RFC 822 位址(包含人名)組成的 tuple。否則回傳一個 400 或更大的 SMTP 錯誤碼以及一個錯誤字串。備註
許多網站會停用 SMTP 的
VRFY以阻擋垃圾郵件發送者。
- SMTP.login(user, password, *, initial_response_ok=True)¶
登入一個需要身分驗證的 SMTP 伺服器。引數為用來驗證的使用者名稱和密碼。如果此 session 之前沒有過
EHLO或HELO指令,此方法會先嘗試 ESMTP 的EHLO。如果身分驗證成功,此方法會正常回傳,否則可能引發以下例外:SMTPHeloError伺服器沒有正確地回覆
HELO問候。SMTPAuthenticationError伺服器不接受該使用者名稱/密碼組合。
SMTPNotSupportedError伺服器不支援
AUTH指令。SMTPException找不到合適的身分驗證方法。
如果伺服器宣告支援
smtplib所支援的每一種身分驗證方法,這些方法會被依序嘗試。支援的身分驗證方法清單請參閱auth()。initial_response_ok 會被傳遞給auth()。選用的關鍵字引數 initial_response_ok 指定對於支援它的身分驗證方法,是否可以將 RFC 4954 中所指定的「initial response(初始回應)」隨
AUTH指令一起傳送,而非要求進行 challenge(質詢)/response(回應)。在 3.5 版的變更: 可能會引發
SMTPNotSupportedError,並新增了 initial_response_ok 參數。
- SMTP.auth(mechanism, authobject, *, initial_response_ok=True)¶
為指定的身分驗證 mechanism 發出一個
SMTPAUTH指令,並透過 authobject 處理 challenge 回應。mechanism 指定要用作
AUTH指令引數的身分驗證機制;有效值為esmtp_features的auth元素中所列出的那些。authobject 必須是一個接受單一選用引數的可呼叫物件:
data = authobject(challenge=None)
如果選用的關鍵字引數 initial_response_ok 為真,
authobject()會先在不帶引數的情況下被呼叫。它可以回傳 RFC 4954 的「initial response(初始回應)」ASCIIstr,該回應會如下被編碼並隨AUTH指令一起傳送。如果authobject()不支援初始回應(例如因為它需要一個 challenge),則它在以challenge=None被呼叫時應回傳None。如果 initial_response_ok 為假,則authobject()不會先以None被呼叫。如果初始回應檢查回傳
None,或者如果 initial_response_ok 為假,authobject()會被呼叫以處理伺服器的 challenge 回應;傳遞給它的 challenge 引數會是一個bytes。它應回傳會被 base64 編碼並傳送至伺服器的 ASCIIstrdata。SMTP類別為CRAM-MD5、PLAIN和LOGIN機制提供了authobjects;它們分別被命名為SMTP.auth_cram_md5、SMTP.auth_plain和SMTP.auth_login。它們都要求SMTP實例的user和password屬性被設定為適當的值。使用者程式碼通常不需要直接呼叫
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。如果此 session 之前沒有過
EHLO或HELO指令,此方法會先嘗試 ESMTP 的EHLO。在 3.12 版的變更: 已棄用的 keyfile 和 certfile 參數已被移除。
SMTPHeloError伺服器沒有正確地回覆
HELO問候。SMTPNotSupportedError伺服器不支援 STARTTLS 擴充。
RuntimeError你的 Python 直譯器無法使用 SSL/TLS 支援。
在 3.3 版的變更: 新增 context。
在 3.4 版的變更: 此方法現在支援以
ssl.SSLContext.check_hostname進行主機名稱檢查以及 Server Name Indicator(請參閱HAS_SNI)。在 3.5 版的變更: 針對缺乏 STARTTLS 支援所引發的錯誤現在是
SMTPNotSupportedError子類別,而非基底的SMTPException。
- SMTP.sendmail(from_addr, to_addrs, msg, mail_options=(), rcpt_options=())¶
寄送郵件。必要引數為一個 RFC 822 寄件位址字串、一個 RFC 822 收件位址字串的 list(單一字串會被視為含有 1 個位址的 list),以及一個訊息字串。呼叫者可以傳入一個 ESMTP 選項的 list(例如
"8bitmime")作為 mail_options,供MAIL FROM指令使用。應與所有RCPT指令一起使用的 ESMTP 選項(例如DSN指令)可以作為 rcpt_options 傳入。每個選項都應作為一個包含該選項完整文字的字串傳入,包括任何可能的鍵(例如"NOTIFY=SUCCESS,FAILURE")。(如果你需要對不同的收件者使用不同的 ESMTP 選項,你必須使用如mail()、rcpt()和data()等低階方法來寄送訊息。)備註
from_addr 和 to_addrs 參數用來建構傳輸代理(transport agent)所使用的訊息信封(message envelope)。
sendmail不會以任何方式修改訊息標頭。msg 可以是一個包含 ASCII 範圍內字元的字串,或者一個位元組字串。字串會使用 ascii codec 被編碼為位元組,而單獨的
\r和\n字元會被轉換為\r\n字元。位元組字串不會被修改。如果此 session 之前沒有過
EHLO或HELO指令,此方法會先嘗試 ESMTP 的EHLO。如果伺服器支援 ESMTP,訊息大小和每個指定的選項都會被傳遞給它(如果該選項在伺服器宣告的功能集合中)。如果EHLO失敗,則會嘗試HELO並抑制 ESMTP 選項。如果郵件至少被一個收件者接受,此方法會正常回傳。否則它會引發一個例外。也就是說,如果此方法沒有引發例外,那麼應該會有人收到你的郵件。如果此方法沒有引發例外,它會回傳一個 dictionary,其中每個被拒絕的收件者都有一個條目。每個條目都包含一個由 SMTP 錯誤碼和伺服器所傳送的隨附錯誤訊息組成的 tuple。
如果
SMTPUTF8被包含在 mail_options 中且伺服器支援它,則 from_addr 和 to_addrs 可以包含非 ASCII 字元。此方法可能引發以下例外:
SMTPRecipientsRefused所有收件者都被拒絕。沒有人收到郵件。
SMTPHeloError伺服器沒有正確地回覆
HELO問候。SMTPSenderRefused伺服器不接受 from_addr。
SMTPDataError伺服器以一個非預期的錯誤碼回覆(而非拒絕某個收件者)。
SMTPNotSupportedErrormail_options 中有給定
SMTPUTF8,但伺服器不支援它。
除非另有說明,否則即使在引發例外後,連線仍會保持開啟。
在 3.2 版的變更: msg 可以是一個位元組字串。
在 3.5 版的變更: 新增
SMTPUTF8支援,且如果指定了SMTPUTF8但伺服器不支援它,可能會引發SMTPNotSupportedError。
- SMTP.send_message(msg, from_addr=None, to_addrs=None, mail_options=(), rcpt_options=())¶
這是一個便利方法,用於以一個
email.message.Message物件所表示的訊息呼叫sendmail()。引數的意義與sendmail()的相同,但 msg 是一個Message物件。如果 from_addr 為
None或 to_addrs 為None,send_message會依 RFC 5322 中所指定的方式,以從 msg 的標頭中擷取出的位址填入這些引數:如果 Sender 欄位存在,from_addr 會被設為該欄位,否則設為 From 欄位。to_addrs 會結合 msg 中 To、Cc 和 Bcc 欄位的值(如果有的話)。如果訊息中剛好出現一組 Resent-* 標頭,則一般的標頭會被忽略,並改用 Resent-* 標頭。如果訊息包含超過一組 Resent-* 標頭,則會引發ValueError,因為無法明確地偵測出最近的那組 Resent- 標頭。send_message會使用BytesGenerator並以\r\n作為 linesep 來序列化 msg,並呼叫sendmail()來傳輸產生的訊息。無論 from_addr 和 to_addrs 的值為何,send_message都不會傳輸 msg 中可能出現的任何 Bcc 或 Resent-Bcc 標頭。如果 from_addr 和 to_addrs 中有任何位址包含非 ASCII 字元,且伺服器未宣告支援SMTPUTF8,則會引發SMTPNotSupportedError。否則Message會以其policy的副本(其中utf8屬性被設為True)進行序列化,且SMTPUTF8和BODY=8BITMIME會被新增到 mail_options。在 3.2 版被加入.
在 3.5 版被加入: 對國際化位址(
SMTPUTF8)的支援。
- SMTP.quit()¶
終止 SMTP session 並關閉連線。回傳 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):")
# 在開頭加上 From: 和 To: 標頭!
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:範例。