smtplib — SMTP 協議客戶端

原始碼: Lib/smtplib.py


smtplib 模組定義了一個 SMTP 客戶端會話物件,該物件可用於向任何具有 SMTP 或 ESMTP 監聽守護程式的 Internet 計算機發送郵件。 有關 SMTP 和 ESMTP 操作的詳細資訊,請參考 RFC 821 (簡單郵件傳輸協議) 和 RFC 1869 (SMTP 服務擴充套件)。

可用性: 不支援 WASI。

此模組在 WebAssembly 上不起作用或不可用。 有關更多資訊,請參閱 WebAssembly 平臺

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

SMTP 例項封裝了一個 SMTP 連線。它具有支援完整 SMTP 和 ESMTP 操作的方法。如果給出了可選的 hostport 引數,則在初始化期間使用這些引數呼叫 SMTP connect() 方法。 如果指定了 local_hostname,則在 HELO/EHLO 命令中用作本地主機的 FQDN。 否則,使用 socket.getfqdn() 查詢本地主機名。 如果 connect() 呼叫返回除成功程式碼之外的任何內容,則會引發 SMTPConnectError。 可選的 timeout 引數指定阻塞操作(如連線嘗試)的超時時間(以秒為單位)(如果未指定,則將使用全域性預設超時設定)。如果超時到期,則會引發 TimeoutError。 可選的 source_address 引數允許在具有多個網路介面的計算機中繫結到某個特定的源地址,和/或繫結到某個特定的源 TCP 埠。它採用 2 元組 (host, port),以便套接字在連線之前繫結到其作為源地址。 如果省略(或者如果 hostport 分別是 '' 和/或 0),將使用作業系統預設行為。

在正常使用中,您應該只需要初始化/連線、sendmail()SMTP.quit() 方法。 下面包含一個示例。

SMTP 類支援 with 語句。 像這樣使用時,當 with 語句退出時,會自動發出 SMTP QUIT 命令。 例如:

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

所有命令都會引發 審計事件 smtplib.SMTP.send,其引數為 selfdata,其中 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 例項完全相同。 SMTP_SSL 應該用於從連線開始就需要 SSL 並且不適合使用 starttls() 的情況。 如果未指定 host,則使用本地主機。 如果 port 為零,則使用標準的 SMTP over SSL 埠 (465)。可選引數 local_hostnametimeoutsource_address 與在 SMTP 類中的含義相同。 context 也是可選的,可以包含一個 SSLContext,並允許配置安全連線的各個方面。 請閱讀 安全注意事項 以瞭解最佳實踐。

在 3.3 版本中更改: 添加了 context

在 3.3 版本中更改: 添加了 source_address 引數。

在 3.4 版本中更改: 該類現在支援使用 ssl.SSLContext.check_hostname伺服器名稱指示的主機名檢查(請參閱 ssl.HAS_SNI)。

在 3.9 版本中更改: 如果 timeout 引數設定為零,則會引發 ValueError,以防止建立非阻塞套接字。

在 3.12 版本中更改: 已刪除已棄用的 keyfilecertfile 引數。

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

LMTP 協議與 ESMTP 非常相似,它很大程度上基於標準的 SMTP 客戶端。LMTP 通常使用 Unix 套接字,因此我們的 connect() 方法必須同時支援 Unix 套接字和常規的 host:port 伺服器。可選引數 local_hostnamesource_addressSMTP 類中的含義相同。要指定 Unix 套接字,您必須使用 host 的絕對路徑,以 '/' 開頭。

支援使用常規 SMTP 機制進行身份驗證。當使用 Unix 套接字時,LMTP 通常不支援或不需要任何身份驗證,但具體情況可能會有所不同。

在 3.9 版本中更改: 添加了可選的 timeout 引數。

還定義了一系列很好的異常。

exception smtplib.SMTPException

OSError 的子類,是此模組提供的所有其他異常的基類。

在 3.4 版本中更改: SMTPException 成為 OSError 的子類

exception smtplib.SMTPServerDisconnected

當伺服器意外斷開連線,或嘗試在連線到伺服器之前使用 SMTP 例項時,將引發此異常。

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 身份驗證出錯。很可能是伺服器不接受提供的使用者名稱/密碼組合。

另請參閱

RFC 821 - 簡單郵件傳輸協議

SMTP 的協議定義。本文件涵蓋了 SMTP 的模型、操作規程和協議詳細資訊。

RFC 1869 - SMTP 服務擴充套件

SMTP 的 ESMTP 擴充套件的定義。這描述了一個使用新命令擴充套件 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)

連線到給定埠上的主機。預設值是連線到標準 SMTP 埠 (25) 上的本地主機。如果主機名以冒號 (':') 後跟一個數字結尾,則該字尾將被剝離,並且該數字將被解釋為要使用的埠號。如果在例項化期間指定了主機,則此方法會自動由建構函式呼叫。返回伺服器在其連線響應中傳送的響應程式碼和訊息的 2 元組。

引發一個 審計事件 smtplib.connect,其中包含引數 selfhostport

SMTP.helo(name='')

使用 HELO 向 SMTP 伺服器標識自己。主機名引數預設為本地主機的完全限定域名。伺服器返回的訊息儲存為物件的 helo_resp 屬性。

在正常操作中,不需要顯式呼叫此方法。必要時,sendmail() 會隱式呼叫它。

SMTP.ehlo(name='')

使用 EHLO 向 ESMTP 伺服器標識自己。主機名引數預設為本地主機的完全限定域名。檢查響應中的 ESMTP 選項,並將其儲存以供 has_extn() 使用。還設定幾個資訊性屬性:伺服器返回的訊息儲存為 ehlo_resp 屬性,does_esmtp 根據伺服器是否支援 ESMTP 設定為 TrueFalse,並且 esmtp_features 將是一個字典,其中包含此伺服器支援的 SMTP 服務擴充套件的名稱及其引數(如果有)。

除非你希望在傳送郵件前使用 has_extn(),否則通常不需要顯式呼叫此方法。 當必要時,sendmail() 會隱式呼叫它。

SMTP.ehlo_or_helo_if_needed()

如果當前會話之前沒有傳送過 EHLOHELO 命令,此方法將呼叫 ehlo() 和/或 helo()。 它會首先嚐試 ESMTP EHLO

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 伺服器上登入。 引數是用於身份驗證的使用者名稱和密碼。 如果當前會話之前沒有傳送過 EHLOHELO 命令,此方法將首先嚐試 ESMTP EHLO。 如果身份驗證成功,此方法將正常返回,否則可能會引發以下異常

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_featuresauth 元素中列出的值。

authobject 必須是可呼叫的物件,它接受一個可選的單個引數。

data = authobject(challenge=None)

如果可選關鍵字引數 initial_response_ok 為 true,則將首先呼叫不帶引數的 authobject()。 它可以返回 RFC 4954 中的“初始響應” ASCII str,該字串將被編碼並與 AUTH 命令一起傳送,如下所示。 如果 authobject() 不支援初始響應(例如,因為它需要質詢),則當使用 challenge=None 呼叫時,它應返回 None。 如果 initial_response_ok 為 false,則不會首先使用 None 呼叫 authobject()

如果初始響應檢查返回 None,或者如果 initial_response_ok 為 false,則將呼叫 authobject() 來處理伺服器的質詢響應;傳遞給它的 challenge 引數將是一個 bytes。 它應該返回 ASCII str data,該 data 將進行 base64 編碼併發送到伺服器。

SMTP 類為 CRAM-MD5PLAINLOGIN 機制提供了 authobjects;它們分別命名為 SMTP.auth_cram_md5SMTP.auth_plainSMTP.auth_login。 它們都要求將 SMTP 例項的 userpassword 屬性設定為適當的值。

使用者程式碼通常不需要直接呼叫 auth,而是可以呼叫 login() 方法,該方法將依次嘗試上述每種機制,按列出的順序排列。auth 的公開是為了方便實現 smtplib 未直接(或尚未)支援的身份驗證方法。

在 3.5 版本中新增。

SMTP.starttls(*, context=None)

將 SMTP 連線置於 TLS(傳輸層安全性)模式。 之後的所有 SMTP 命令都將被加密。 然後,您應再次呼叫 ehlo()

如果提供了 keyfilecertfile,則它們用於建立 ssl.SSLContext

可選的 context 引數是一個 ssl.SSLContext 物件; 這是使用金鑰檔案和證書檔案的替代方法,如果指定了該物件,則 keyfilecertfile 都應為 None

如果當前會話之前沒有傳送過 EHLOHELO 命令,此方法將首先嚐試 ESMTP EHLO

在 3.12 版本中更改: 已刪除已棄用的 keyfilecertfile 引數。

SMTPHeloError

伺服器沒有正確響應 HELO 問候語。

SMTPNotSupportedError

伺服器不支援 STARTTLS 擴充套件。

RuntimeError

您的 Python 直譯器無法使用 SSL/TLS 支援。

在 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 FROM 命令中作為 mail_options 使用。應該與所有 RCPT 命令一起使用的 ESMTP 選項(例如 DSN 命令)可以作為 rcpt_options 傳遞。(如果您需要對不同的收件人使用不同的 ESMTP 選項,則必須使用低階方法(例如 mail()rcpt()data())來發送訊息。)

注意

from_addrto_addrs 引數用於構造傳輸代理使用的訊息信封。sendmail 不會以任何方式修改訊息頭。

msg 可以是包含 ASCII 範圍字元的字串或位元組字串。字串使用 ascii 編解碼器編碼為位元組,並且單獨的 \r\n 字元會轉換為 \r\n 字元。位元組字串不會被修改。

如果此會話中之前沒有 EHLOHELO 命令,則此方法會首先嚐試 ESMTP EHLO。如果伺服器執行 ESMTP,則訊息大小和每個指定的選項都將傳遞給它(如果該選項在伺服器通告的功能集中)。如果 EHLO 失敗,則將嘗試 HELO 並取消 ESMTP 選項。

如果郵件至少被一個收件人接受,此方法將正常返回。否則,它會引發異常。也就是說,如果此方法沒有引發異常,則應該有人收到您的郵件。如果此方法沒有引發異常,則它會返回一個字典,其中包含每個被拒絕的收件人的一個條目。每個條目包含一個由 SMTP 錯誤程式碼和伺服器傳送的隨附錯誤訊息組成的元組。

如果 mail_options 中包含 SMTPUTF8,並且伺服器支援它,則 from_addrto_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_addrNoneto_addrsNone,則 send_message 會使用從 msg 的頭中提取的地址來填充這些引數,如 RFC 5322 中所指定的:如果存在 Sender 欄位,則 from_addr 設定為該欄位,否則設定為 From 欄位。to_addrs 組合了 msgToCcBcc 欄位的值(如果有)。如果訊息中恰好出現一組 Resent-* 標頭,則會忽略常規標頭,並改用 Resent-* 標頭。如果訊息包含多組 Resent-* 標頭,則會引發 ValueError,因為無法明確檢測到最新的一組 Resent- 標頭。

send_message 使用 BytesGeneratormsg 序列化,並將 \r\n 作為 linesep,並呼叫 sendmail() 來傳輸生成的訊息。無論 from_addrto_addrs 的值如何,send_message 都不會傳輸可能出現在 msg 中的任何 BccResent-Bcc 標頭。如果 from_addrto_addrs 中的任何地址包含非 ASCII 字元,並且伺服器不通告 SMTPUTF8 支援,則會引發 SMTPNotSupported 錯誤。否則,將使用其 policy 的克隆(其中 utf8 屬性設定為 True)來序列化 Message,並將 SMTPUTF8BODY=8BITMIME 新增到 mail_options

3.2 版本中新增。

3.5 版本新增: 對國際化地址的支援 (SMTPUTF8)。

SMTP.quit()

終止 SMTP 會話並關閉連線。返回 SMTP QUIT 命令的結果。

還支援與標準 SMTP/ESMTP 命令 HELPRSETNOOPMAILRCPTDATA 相對應的低階方法。通常不需要直接呼叫這些方法,因此此處不作介紹。有關詳細資訊,請查閱模組程式碼。

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: 示例