21.17. smtplib — SMTP (简单邮件传输协议) 客户端

源代码: Lib/smtplib.py


The smtplib 模块定义 SMTP 客户端会话对象,可以用于将邮件发送给采用 SMTP 或 ESMTP 监听器守护程序的任何 Internet 机器。对于 SMTP 和 ESMTP 操作的细节,请翻阅 RFC 821 (简单邮件传输协议) 和 RFC 1869 (SMTP 服务扩展)。

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

An SMTP 实例封装 SMTP 连接。它拥有支持 SMTP 和 ESMTP 操作的全部技能方法。若有给出可选主机和端口参数,SMTP connect() 方法被调用采用这些参数在初始化期间。若指定, local_hostname 在 HELO/EHLO 命令中被用作本地主机的 FQDN (完全合格域名)。否则,查找本地主机名使用 socket.getfqdn() 。若 connect() 调用返回任何内容除成功代码外, SMTPConnectError 被引发。可选 timeout 参数指定超时 (以秒为单位) 为阻塞像连接尝试操作 (若未指定,将使用全局默认超时设置)。若超时到期, socket.timeout is raised. The optional source_address parameter allows to bind to some specific source address in a machine with multiple network interfaces, and/or to some specific source TCP port. It takes a 2-tuple (host, port), for the socket to bind to as its source address before connecting. If omitted (or if host or port are '' 和/或 0 分别) 将使用 OS 默认行为。

对于正常使用,应该仅要求初始化/连接, sendmail() ,和 quit() 方法。包括下文范例。

The SMTP 类支持 with 语句。当像这样使用时,SMTP QUIT 命令被自动发出当 with 语句退出。如:

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

3.3 版改变: 支持 with 语句被添加。

3.3 版改变: 添加 source_address 自变量。

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

An SMTP_SSL 实例行为准确如同实例化的 SMTP . SMTP_SSL 应该用于从连接开始就要求 SSL 的情况且使用 starttls() 不合适。若 host 未指定,使用本地主机。若 port 为 0,使用标准 SMTP-over-SSL 端口 465。可选自变量 local_hostname , timeout and source_address 拥有的含义如同它们在 SMTP 类。 context ,也是可选的,可以包含 SSLContext and allows to configure various aspects of the secure connection. Please read 安全注意事项 了解最佳实践。

keyfile and certfile 是传统替代对于 context ,且可以指向用于 SSL 连接的 PEM 格式私钥和证书链文件。

3.3 版改变: context 被添加。

3.3 版改变: 添加 source_address 自变量。

3.4 版改变: 类现在支持主机名校验采用 ssl.SSLContext.check_hostname and SNI (服务器名称指示) (见 ssl.HAS_SNI ).

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

LMTP 协议非常类似于 ESMTP,重点基于标准 SMTP 客户端。很大程度上基于标准 SMTP 客户端。LMTP 使用 Unix 套接字很常见,因此 connect() 方法必须支持这及常规 host:port 服务器。可选自变量 local_hostname 和 source_address 拥有相同含义如它们在 SMTP 类。要指定 Unix 套接字,必须使用绝对路径对于 host ,采用 / 开头。

支持使用常规 SMTP 机制进行身份验证。当使用 Unix 套接字时,LMTP 一般不支持或不要求任何身份验证,但具体情况可能有所不同。

还定义了一些不错异常:

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. SMTPAuthenticationError

SMTP 身份验证出错。服务器很可能不接受提供的用户名/口令组合。

另请参阅

RFC 821 - SMTP (简单邮件传输协议)
Protocol definition for SMTP. This document covers the model, operating procedure, and protocol details for SMTP.
RFC 1869 - ESMTP (SMTP 服务扩展)
Definition of the ESMTP extensions for SMTP. This describes a framework for extending SMTP with new commands, supporting dynamic discovery of the commands provided by the server, and defines a few additional commands.

21.17.1. SMTP 对象

An SMTP 实例具有下列方法:

SMTP. set_debuglevel ( level )

Set the debug output level. A true value for level results in debug messages for connection and for all messages sent to and received from the server.

SMTP. docmd ( cmd , args='' )

发送命令 cmd 到服务器。可选自变量 args 简单串联命令,以空格分隔。

这返回由数值响应代码和实际响应行组成的 2 元素元组 (多行响应会拼接成一长行)。

在正常操作中,明确调用此方法应该不必要。它用于实现其它方法,且可能对测试私有扩展很有用。

若丢失服务器连接当等待回复时, SMTPServerDisconnected 会被引发。

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

连接到给出端口的主机。默认连接到本地主机在标准 SMTP 25 端口。若主机名结尾带冒号 ( ':' ) 后紧跟数字,将剥离该后缀和将数字解释为要使用的端口号。构造函数会自动援引此方法,若有指定主机在实例化期间。返回服务器在其连接响应中发送的 2 元素元组 (响应代码和消息)。

SMTP. helo ( name='' )

标识自己到 SMTP 服务器使用 HELO 。主机名自变量默认为本地主机的完全合格域名。由服务器返回的消息被存储作为 helo_resp 属性对于对象。

在正常操作中,明确调用此方法应该不必要。它被隐式调用通过 sendmail() 当有必要时。

SMTP. ehlo ( name='' )

标识自己到 ESMTP 服务器使用 EHLO 。主机名自变量默认为本地主机的完全合格域名。审查 ESMTP 选项的响应并存储它们以供使用通过 has_extn() 。还设置了几个情报属性:由服务器返回的消息被存储作为 ehlo_resp 属性, does_esmtp 被设为 True 或 False 取决于服务器是否支持 ESMTP,和 esmtp_features 将是包含此服务器支持的 SMTP 服务扩展名称及其参数 (若有的话) 的字典。

除非希望使用 has_extn() 在发送邮件之前,明确调用此方法应该不必要。它被隐式调用通过 sendmail() 当有必要时。

SMTP. ehlo_or_helo_if_needed ( )

This method call ehlo() and or helo() 若先前没有 EHLO or HELO 命令此会话。它将尝试 ESMTP EHLO 首先。

SMTPHeloError
服务器没有正确回复 HELO 问候。
SMTP. has_extn ( name )

返回 True if name 在由服务器返回的一组 SMTP 服务扩展中, False 否则。大小写被忽略。

SMTP. verify ( address )

校验此服务器地址的有效性使用 SMTP VRFY 。返回的元组包含代码 250 和完整 RFC 822 地址 (包括人类姓名) 若用户地址有效。否则返回 400 或更大的 SMTP 错误代码和错误字符串。

注意

很多站点禁用 SMTP VRFY 为挫败垃圾邮件发送者。

SMTP. login ( user , password )

登录要求身份验证的 SMTP 服务器。参数是要进行身份验证的用户名和口令。若先前没有 EHLO or HELO 命令此会话,此方法将尝试 ESMTP EHLO 首先。此方法将正常返回若身份验证成功,或可能引发下列异常:

SMTPHeloError
服务器没有正确回复 HELO 问候。
SMTPAuthenticationError
服务器不接受用户名/口令组合。
SMTPException
模块未找到合适的身份验证方法。
SMTP. starttls ( keyfile=None , certfile=None , context=None )

将 SMTP 连接置于 TLS (传输层安全) 模式。随后的所有 SMTP 命令将被加密。然后应该调用 ehlo() 再次。

keyfile and certfile are provided, these are passed to the socket 模块的 ssl() 函数。

可选 context parameter is a ssl.SSLContext 对象;这是使用 keyfile 和 certfile 的替代,若指定 keyfile and certfile should be None.

若先前没有 EHLO or HELO 命令此会话,此方法将尝试 ESMTP EHLO 首先。

SMTPHeloError
服务器没有正确回复 HELO 问候。
SMTPException
服务器不支持 STARTTLS 扩展。
RuntimeError
SSL/TLS 支持不可用于 Python 解释器。

3.3 版改变: context 被添加。

3.4 版改变: 方法现在支持主机名校验采用 SSLContext.check_hostname and SNI (服务器名称指示器) (见 HAS_SNI ).

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

发送邮件。要求自变量为 RFC 822 from_addr 字符串,列表的 RFC 822 to_addr 字符串 (裸字符串将被视为具有 1 地址的列表) 和消息字符串。调用者可以传递 ESMTP 选项列表 (譬如 8bitmime ) 以用于 MAIL FROM 命令作为 mail_options 。ESMTP 选项 (譬如 DSN 命令) 应该用于所有 RCPT 命令可以传递作为 rcpt_options 。(若需要对不同收件人使用不同 ESMTP 选项,就必须使用低级方法,譬如 mail() , rcpt() and data() 以发送消息。)

注意

The from_addr and to_addrs 参数用于构造传输代理所使用的消息信封。 sendmail 不会以任何方式修改消息 Header 头。

msg 可以是包含 ASCII 范围字符的字符串,或字节字符串。使用 ASCII 编解码器将字符串编码成字节,和单独 \r and \n 字符被转换成 \r\n 字符。不修改字节字符串。

若先前没有 EHLO or HELO 命令此会话,此方法将尝试 ESMTP EHLO 首先。若服务器执行 ESMTP,将把消息大小和每个指定选项传递给它 (若选项在服务器公布的特征集中)。若 EHLO 失败, HELO 将尝试并抑制 ESMTP 选项。

此方法将正常返回若至少一收件人接受邮件。否则会引发异常。也就是说,若此方法不引发异常,那么有人应该收到邮件。若此方法未引发异常,返回对于每个被拒绝的收件人是一条目的字典。每一条目包含元组 (SMTP 错误码,由服务器发送伴随的错误消息)。

此方法可能引发下列异常:

SMTPRecipientsRefused
所有收件人被拒绝。没有人收到邮件。 recipients attribute of the exception object is a dictionary with information about the refused recipients (like the one returned when at least one recipient was accepted).
SMTPHeloError
服务器没有正确回复 HELO 问候。
SMTPSenderRefused
服务器不接受 from_addr .
SMTPDataError
The server replied with an unexpected error code (other than a refusal of a recipient).

除非另有说明,连接会被打开即使引发异常。

3.2 版改变: msg 可以是 byte 字符串。

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

这是方便方法为调用 sendmail() 采用的消息表示通过 email.message.Message 对象。自变量有相同含义如 sendmail() ,除了 msg Message 对象。

from_addr is None or to_addrs is None , send_message 填充这些自变量采用的提取地址来自 Header 头对于 msg 作为指定在 RFC 2822 : from_addr 被设为 Sender 字段若存在,否则被设为 字段。 to_adresses 组合值 (若有的话) 对于 , Cc ,和 Bcc 字段从 msg 。若恰好有一组 Resent-* 头出现在消息中,常规 Header 头被忽略和 Resent-* 头被使用以取而代之。若消息包含多组 Resent-* 头, ValueError 被引发,由于没有办法明确检测到最近一组 Resent- 头。

send_message 序列化 msg 使用 BytesGenerator with \r\n 作为 linesep ,和调用 sendmail() 以传输结果消息。不管值 from_addr and to_addrs , send_message 不传输任何 Bcc or Resent-Bcc 头可能出现在 msg .

3.2 版新增。

SMTP. quit ( )

终止 SMTP 会话并关闭连接。 返回的结果源于 SMTP QUIT 命令。

低级方法对应标准 SMTP/ESMTP 命令 HELP , RSET , NOOP , MAIL , RCPT ,和 DATA 也支持。通常不需要直接调用这些,所以这里未文档化它们。有关细节,请翻阅模块代码。

21.17.2. SMTP 范例

此范例提示用户输入消息信封所需的地址(To 和 From 地址) 和要交付的消息。注意,要包括在消息中的 Header 头还必须包括在键入消息中;此范例不做任何处理对于 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 包的特征来构造 Email 消息,那么可以发送它凭借 send_message() ;见 Email:范例 .