21.17. 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()
方法即可。下文包括了一个示例。The
SMTP
class supports thewith
statement. When used like this, the SMTPQUIT
command is issued automatically when thewith
statement exits. E.g.:>>> 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 认证出现问题。 最大的可能是服务器不接受所提供的用户名/密码组合。
参见
21.17.1. 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 发送
SMTP
AUTH
命令,并通过 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 进行编码的 ASCIIstr
data 并发送给服务器。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
。如果这个会话中没有先前的
EHLO
orHELO
命令,该方法会首先尝试 ESMTPEHLO
。3.6 版后已移除: keyfile 和 certfile 已弃用并转而推荐 context。 请改用
ssl.SSLContext.load_cert_chain()
或让ssl.create_default_context()
为你选择系统所信任的 CA 证书。SMTPHeloError
服务器没有正确回复
HELO
问候。SMTPNotSupportedError
服务器不支持 STARTTLS 扩展。
RuntimeError
SSL/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
对应的低层级方法也是受支持的。 通常不需要直接调用这些方法,因此它们没有被写入本文档。 相关细节请参看模块代码。
21.17.2. 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: 示例。