smtplib
— SMTP 协议客户端¶
源代码: Lib/smtplib.py
smtplib
模块定义了一个 SMTP 客户端会话对象,可用于将邮件发送到任何具有 SMTP 或 ESMTP 监听守护进程的互联网机器。有关 SMTP 和 ESMTP 操作的详细信息,请参阅 RFC 821(简单邮件传输协议)和 RFC 1869(SMTP 服务扩展)。
可用性: 不适用于 Emscripten,不适用于 WASI。
此模块在 WebAssembly 平台 wasm32-emscripten
和 wasm32-wasi
上不可用或无法工作。有关更多信息,请参阅 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
语句。像这样使用时,SMTPQUIT
命令会在with
语句退出时自动发出。例如:>>> 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()
方法必须支持该协议以及常规的 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 元组,其中包含服务器在其连接响应中发送的响应代码和消息。引发带有参数
self
、host
、port
的 审计事件smtplib.connect
。
- 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
。它应该返回将进行 base64 编码并发送到服务器的 ASCIIstr
data。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=())¶
这是一个方便的方法,用于在消息由
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
将 *msg* 序列化,其中 *linesep* 为\r\n
,并调用sendmail()
来传输生成的邮件。无论 *from_addr* 和 *to_addrs* 的值是什么,send_message
都不会传输 *msg* 中可能出现的任何 *Bcc* 或 *Resent-Bcc* 标头。如果 *from_addr* 和 *to_addrs* 中的任何地址包含非 ASCII 字符,并且服务器未声明支持SMTPUTF8
,则会引发SMTPNotSupported
错误。否则,将使用其policy
的克隆来序列化Message
,其中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
对应的低级方法。通常不需要直接调用这些方法,因此这里不作介绍。有关详细信息,请参阅模块代码。
SMTP 示例¶
此示例提示用户输入邮件信封中所需的地址(“收件人”和“发件人”地址)以及要传递的邮件。请注意,要包含在邮件中的标头必须包含在输入的邮件中;此示例不执行对 RFC 822 标头的任何处理。特别是,“收件人”和“发件人”地址必须明确包含在邮件标头中
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()
发送;请参阅 电子邮件:示例。