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 操作的方法。如果给出了可选的 host 和 port 参数,则在初始化期间使用这些参数调用 SMTPconnect()
方法。 如果指定了 local_hostname,则在 HELO/EHLO 命令中用作本地主机的 FQDN。 否则,使用socket.getfqdn()
查找本地主机名。 如果connect()
调用返回除成功代码之外的任何内容,则会引发SMTPConnectError
。 可选的 timeout 参数指定阻塞操作(如连接尝试)的超时时间(以秒为单位)(如果未指定,则将使用全局默认超时设置)。如果超时到期,则会引发TimeoutError
。 可选的 source_address 参数允许在具有多个网络接口的计算机中绑定到某个特定的源地址,和/或绑定到某个特定的源 TCP 端口。它采用 2 元组(host, port)
,以便套接字在连接之前绑定到其作为源地址。 如果省略(或者如果 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') >>>
所有命令都会引发 审计事件
smtplib.SMTP.send
,其参数为self
和data
,其中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_hostname、timeout 和 source_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 版本中更改: 已删除已弃用的 keyfile 和 certfile 参数。
- class smtplib.LMTP(host='', port=LMTP_PORT, local_hostname=None, source_address=None[, timeout])¶
LMTP 协议与 ESMTP 非常相似,它很大程度上基于标准的 SMTP 客户端。LMTP 通常使用 Unix 套接字,因此我们的
connect()
方法必须同时支持 Unix 套接字和常规的 host:port 服务器。可选参数 local_hostname 和 source_address 与SMTP
类中的含义相同。要指定 Unix 套接字,您必须使用 host 的绝对路径,以 '/' 开头。支持使用常规 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¶
发件人地址被拒绝。除了在所有
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 身份验证出错。很可能是服务器不接受提供的用户名/密码组合。
另请参阅
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
,其中包含参数self
、host
、port
。
- SMTP.helo(name='')¶
使用
HELO
向 SMTP 服务器标识自己。主机名参数默认为本地主机的完全限定域名。服务器返回的消息存储为对象的helo_resp
属性。在正常操作中,不需要显式调用此方法。必要时,
sendmail()
会隐式调用它。
- SMTP.ehlo(name='')¶
使用
EHLO
向 ESMTP 服务器标识自己。主机名参数默认为本地主机的完全限定域名。检查响应中的 ESMTP 选项,并将其存储以供has_extn()
使用。还设置几个信息性属性:服务器返回的消息存储为ehlo_resp
属性,does_esmtp
根据服务器是否支持 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 指定对于支持它的身份验证方法,是否可以按照 RFC 4954 中的规定,将“初始响应”与
AUTH
命令一起发送,而不是需要质询/响应。在 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 为 true,则将首先调用不带参数的
authobject()
。 它可以返回 RFC 4954 中的“初始响应” ASCIIstr
,该字符串将被编码并与AUTH
命令一起发送,如下所示。 如果authobject()
不支持初始响应(例如,因为它需要质询),则当使用challenge=None
调用时,它应返回None
。 如果 initial_response_ok 为 false,则不会首先使用None
调用authobject()
。如果初始响应检查返回
None
,或者如果 initial_response_ok 为 false,则将调用authobject()
来处理服务器的质询响应;传递给它的 challenge 参数将是一个bytes
。 它应该返回 ASCIIstr
data,该 data 将进行 base64 编码并发送到服务器。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(传输层安全性)模式。 之后的所有 SMTP 命令都将被加密。 然后,您应再次调用
ehlo()
。如果提供了 keyfile 和 certfile,则它们用于创建
ssl.SSLContext
。可选的 context 参数是一个
ssl.SSLContext
对象; 这是使用密钥文件和证书文件的替代方法,如果指定了该对象,则 keyfile 和 certfile 都应为None
。如果当前会话之前没有发送过
EHLO
或HELO
命令,此方法将首先尝试 ESMTPEHLO
。在 3.12 版本中更改: 已删除已弃用的 keyfile 和 certfile 参数。
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_addr 和 to_addrs 参数用于构造传输代理使用的消息信封。
sendmail
不会以任何方式修改消息头。msg 可以是包含 ASCII 范围字符的字符串或字节字符串。字符串使用 ascii 编解码器编码为字节,并且单独的
\r
和\n
字符会转换为\r\n
字符。字节字符串不会被修改。如果此会话中之前没有
EHLO
或HELO
命令,则此方法会首先尝试 ESMTPEHLO
。如果服务器执行 ESMTP,则消息大小和每个指定的选项都将传递给它(如果该选项在服务器通告的功能集中)。如果EHLO
失败,则将尝试HELO
并取消 ESMTP 选项。如果邮件至少被一个收件人接受,此方法将正常返回。否则,它会引发异常。也就是说,如果此方法没有引发异常,则应该有人收到您的邮件。如果此方法没有引发异常,则它会返回一个字典,其中包含每个被拒绝的收件人的一个条目。每个条目包含一个由 SMTP 错误代码和服务器发送的随附错误消息组成的元组。
如果 mail_options 中包含
SMTPUTF8
,并且服务器支持它,则 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
会使用从 msg 的头中提取的地址来填充这些参数,如 RFC 5322 中所指定的:如果存在 Sender 字段,则 from_addr 设置为该字段,否则设置为 From 字段。to_addrs 组合了 msg 中 To、Cc 和 Bcc 字段的值(如果有)。如果消息中恰好出现一组 Resent-* 标头,则会忽略常规标头,并改用 Resent-* 标头。如果消息包含多组 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
错误。否则,将使用其policy
的克隆(其中utf8
属性设置为True
)来序列化Message
,并将SMTPUTF8
和BODY=8BITMIME
添加到 mail_options。3.2 版本中新增。
3.5 版本新增: 对国际化地址的支持 (
SMTPUTF8
)。
- SMTP.quit()¶
终止 SMTP 会话并关闭连接。返回 SMTP
QUIT
命令的结果。
还支持与标准 SMTP/ESMTP 命令 HELP
、RSET
、NOOP
、MAIL
、RCPT
和 DATA
相对应的低级方法。通常不需要直接调用这些方法,因此此处不作介绍。有关详细信息,请查阅模块代码。
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: 示例。