smtplib — SMTP 协议客户端¶
源代码: Lib/smtplib.py
模块定义了一个 SMTP 客户端会话对象,该对象可用于将邮件发送到任何具有 SMTP 或 ESMTP 监听守护进程的互联网机器。有关 SMTP 和 ESMTP 操作的详细信息,请参阅 RFC 821 (Simple Mail Transfer Protocol) 和 RFC 1869 (SMTP Service Extensions)。smtplib
可用性:非 WASI。
此模块在 WebAssembly 上不起作用或不可用。有关更多信息,请参阅 WebAssembly 平台。
- class smtplib.SMTP(host='', port=0, local_hostname=None, [timeout, ]source_address=None)¶
实例封装了一个 SMTP 连接。它具有支持完整 SMTP 和 ESMTP 操作的方法。如果提供了可选的 host 和 port 参数,则在初始化期间将使用这些参数调用 SMTPSMTP
connect()
方法。如果指定了 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
应用于从连接开始就需要 SSL 且不适合使用SMTP_SSL
starttls()
的情况。如果未指定 host,则使用本地主机。如果 port 为零,则使用标准的 SMTP-over-SSL 端口 (465)。可选参数 local_hostname、timeout 和 source_address 的含义与
类中的相同。context(也是可选的)可以包含一个SMTP
ssl.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 客户端。通常使用 Unix 套接字进行 LMTP,因此我们的
connect()
方法必须同时支持 Unix 套接字和常规的 host:port 服务器。可选参数 local_hostname 和 source_address 的含义与
类中的相同。要指定 Unix 套接字,必须为 host 使用绝对路径,以 '/' 开头。SMTP
支持身份验证,使用常规的 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
会导致有关连接以及发送到服务器和从服务器接收到的所有消息的调试消息。值为 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
设置为True
或False
(取决于服务器是否支持 ESMTP),并且esmtp_features
将是一个包含此服务器支持的 SMTP 服务扩展名称及其参数(如果有)的字典。除非您希望在发送邮件之前使用
has_extn()
,否则通常不需要显式调用此方法。它将在必要时由sendmail()
隐式调用。
- SMTP.ehlo_or_helo_if_needed()¶
此方法将在本会话中没有之前的
EHLO
或HELO
命令时调用ehlo()
和/或helo()
。它首先尝试 ESMTPEHLO
。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 服务器。参数是用户名和用于身份验证的密码。如果本会话中没有先前的
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 的“初始响应”ASCII
str
,它将作为下面的AUTH
命令进行编码和发送。如果 `authobject()` 不支持初始响应(例如,因为它需要质询),则在调用时应返回None
(当 `challenge=None` 时)。如果 initial_response_ok 为 false,则不会先用 `None` 调用 `authobject()`。如果初始响应检查返回
None
,或者 initial_response_ok 为 false,则将调用 `authobject()` 来处理服务器的质询响应;传递给它的 challenge 参数将是一个bytes
。它应该返回 ASCIIstr
data,它将被 base64 编码并发送到服务器。
类为 `CRAM-MD5`、`PLAIN` 和 `LOGIN` 机制提供了 `authobjects`;它们分别命名为 `SMTP.auth_cram_md5`、`SMTP.auth_plain` 和 `SMTP.auth_login`。它们都需要将 `SMTP` 实例的 `user` 和 `password` 属性设置为适当的值。SMTP
用户代码通常不需要直接调用 `auth`,而是可以调用 `login()` 方法,该方法将按列出的顺序尝试上述每个机制。`auth` 是公开的,以便于实现 `smtplib` 未(或尚未)直接支持的身份验证方法的实现。
在 3.5 版本加入。
- SMTP.starttls(*, context=None)¶
将 SMTP 连接置于 TLS (Transport Layer Security) 模式。之后的所有 SMTP 命令都将进行加密。之后应再次调用
ehlo()
。如果提供了 keyfile 和 certfile,则它们用于创建
ssl.SSLContext
。可选的 context 参数是一个
ssl.SSLContext
对象;这是使用 keyfile 和 certfile 的替代方法,如果指定了它,则 keyfile 和 certfile 都应为None
。如果本会话中没有先前的
EHLO
或HELO
命令,则此方法会先尝试 ESMTPEHLO
。在 3.12 版更改: 已移除已弃用的 keyfile 和 certfile 参数。
SMTPHeloError
服务器对
HELO
问候语没有正确响应。SMTPNotSupportedError
服务器不支持 STARTTLS 扩展。
RuntimeError
您的 Python 解释器没有可用的 SSL/TLS 支持。
版本 3.3 中已更改: 添加了 context 参数。
版本 3.4 中已更改: 该方法现在支持使用
ssl.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 个地址的列表)以及一个消息字符串。调用者可以为用于 `MAIL FROM` 命令的邮件信封传递一个 ESMTP 选项列表(例如 `8bitmime`),作为 mail_options。可作为 rcpt_options 传递给所有 `RCPT` 命令的 ESMTP 选项(例如 `DSN` 命令)。(如果需要对不同收件人使用不同的 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
所有收件人都被拒绝。没有人收到邮件。
SMTPHeloError
服务器对
HELO
问候语没有正确响应。SMTPSenderRefused
服务器未接受 from_addr。
SMTPDataError
服务器返回了意外错误代码(除了拒绝收件人之外)。
SMTPNotSupportedError
`SMTPUTF8` 已在 mail_options 中给出,但服务器不支持。
除非另有说明,否则即使引发了异常,连接也会保持打开状态。
版本 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 的头部字段提取地址来填充这些参数:from_addr 设置为 `Sender` 字段(如果存在),否则设置为 `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` 支持,则会引发SMTPNotSupportedError
。否则,将使用其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 实例具有以下属性
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: 示例。