smtplib — SMTP 协议 Client 端

源代码: Lib/smtplib.py


smtplib模块定义 SMTPClient 端会话对象,该对象可用于pass SMTP 或 ESMTP 侦听器守护程序将邮件发送到任何 Internet 计算机。有关 SMTP 和 ESMTP 操作的详细信息,请参阅 RFC 821(简单邮件传输协议)和 RFC 1869(SMTP 服务扩展)。

    • class * smtplib. SMTP(* host ='' port = 0 local_hostname = None *,[* timeout *,] * source_address = None *)
    • SMTP实例封装了 SMTP 连接。它具有支持 SMTP 和 ESMTP 操作的全部Function的方法。如果给出了可选的主机和端口参数,则在初始化期间将使用这些参数调用 SMTP connect()方法。如果指定,* local_hostname 用作 HELO/EHLO 命令中 localhost 的 FQDN。否则,使用socket.getfqdn()找到 localhost 名。如果connect()调用返回成功代码以外的任何内容,则会引发SMTPConnectError。可选的 timeout *参数以秒为单位指定用于阻止诸如连接try之类的操作的超时(如果未指定,将使用全局默认超时设置)。如果超时到期,则socket.timeout被提高。可选的 source_address 参数允许绑定到具有多个网络接口的计算机中的某些特定源地址和/或某些特定源 TCP 端口。连接之前,套接字需要两个 Tuples(主机,端口)绑定为其源地址。如果Ellipsis(或者主机或端口分别为''和/或 0),则将使用 os 默认行为。

对于正常使用,您只需要初始化/连接,sendmail()SMTP.quit()方法。下面包括一个示例。

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

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

所有命令都将引发带有参数selfdataauditing event smtplib.SMTP.send,其中data是将要发送到远程主机的字节。

在版本 3.3 中进行了更改:添加了对with语句的支持。

在版本 3.3 中更改:添加了 source_address 参数。

版本 3.5 中的新增Function:现在支持 SMTPUTF8extensions( 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实例完全相同。 SMTP_SSL应该用于从连接开始就需要 SSL 且不适合使用starttls()的情况。如果未指定* host ,则使用 localhost。如果 port 为零,则使用标准的 SSL 上的 SMTP 端口(465)。可选参数 local_hostname timeout source_address *具有与SMTP类相同的含义。 * context *(也是可选的)可以包含SSLContext并允许配置安全连接的各个方面。请阅读Security considerations以获得最佳做法。
  • 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 非常相似,它很大程度上基于标准的 SMTPClient 端。对于 LMTP,通常使用 Unix 套接字,因此我们的connect()方法必须支持该套接字以及常规的 host:port 服务器。可选参数 local_hostname 和 source_address 具有与SMTP类相同的含义。要指定 Unix 套接字,必须为* host *使用绝对路径,以'/'开头。

使用常规 SMTP 机制支持身份验证。使用 Unix 套接字时,LMTP 通常不支持或不需要任何身份验证,但是您的里程可能会有所不同。

还定义了一个很好的 exception 选择:

  • exception smtplib. SMTPException
    • OSError的子类,它是此模块提供的所有其他异常的基本异常类。

在版本 3.4 中进行了更改:SMTPException 成为OSError的子类

  • exception smtplib. SMTPServerDisconnected

    • 如果服务器意外断开连接,或者在将其连接到服务器之前try使用SMTP实例,则会引发此异常。
  • exception smtplib. SMTPResponseException

    • 所有包含 SMTP 错误代码的异常的 Base Class。在某些情况下,当 SMTP 服务器返回错误代码时,会生成这些异常。错误代码存储在错误的smtp_code属性中,并且smtp_error属性设置为错误消息。
  • exception smtplib. SMTPSenderRefused

    • 发件人地址被拒绝。除了在所有SMTPResponseExceptionexception 中设置的属性外,这还将'sender'设置为 SMTP 服务器拒绝的字符串。
  • exception smtplib. SMTPRecipientsRefused

    • 所有收件人地址均被拒绝。每个收件人的错误都可以pass属性recipients进行访问,该属性是与SMTP.sendmail()返回类型完全相同的字典。
  • exception smtplib. SMTPDataError

    • SMTP 服务器拒绝接受邮件数据。
  • exception smtplib. SMTPConnectError

    • 与服务器构建连接期间发生错误。
  • exception smtplib. SMTPHeloError

    • 服务器拒绝了我们的HELO消息。
  • exception smtplib. SMTPNotSupportedError

    • 服务器不支持try的命令或选项。

3.5 版中的新Function。

  • exception smtplib. SMTPAuthenticationError
    • SMTP 验证出错。服务器很可能不接受提供的用户名/密码组合。

See also

  • RFC 821-简单邮件传输协议

  • SMTP 的协议定义。本文档介绍了 SMTP 的型号,操作过程和协议详细信息。

  • RFC 1869-SMTP 服务扩展

  • SMTP 的 ESMTP 扩展的定义。本文档介绍了用于使用新命令扩展 SMTP,支持动态发现服务器提供的命令的框架,并定义了一些其他命令。

SMTP Objects

SMTP实例具有以下方法:

  • SMTP. set_debuglevel(级别)
    • 设置调试输出级别。 * level *的值为 1 或True会导致连接的调试消息以及发送到服务器和从服务器接收的所有消息。 * level *的值 2 导致这些消息带有时间戳。

在版本 3.5 中进行了更改:添加了调试级别 2.

  • SMTP. docmd(* cmd args =''*)
    • 向服务器发送命令* cmd 。可选参数 args *仅连接到命令,并用空格分隔。

这将返回一个由数字响应代码和实际响应行组成的 2Tuples(多行响应合并为一条长行.)

在正常操作中,不必显式调用此方法。它用于实现其他方法,可能对测试私有扩展有用。

如果在 await 答复时与服务器的连接丢失,则将引发SMTPServerDisconnected

  • SMTP. connect(* host ='localhost' port = 0 *)
    • 连接到给定端口上的主机。默认设置是在标准 SMTP 端口(25)上连接到 localhost。如果主机名以冒号(':')后跟数字结尾,则将删除该后缀,并将该数字解释为要使用的端口号。如果在实例化期间指定了主机,则构造方法会自动调用此方法。返回由服务器在其连接响应中发送的响应代码和消息的 2Tuples。

用参数selfhostport引发auditing event smtplib.connect

  • SMTP. helo(* name =''*)
    • 使用HELO将自己标识为 SMTP 服务器。 hostname 参数默认为 localhost 的标准域名。服务器返回的消息存储为对象的helo_resp属性。

在正常操作中,不必显式调用此方法。必要时它将由sendmail()隐式调用。

  • SMTP. ehlo(* name =''*)
    • 使用EHLO将自己标识为 ESMTP 服务器。 hostname 参数默认为 localhost 的标准域名。检查 ESMTP 选项的响应,并存储它们供has_extn()使用。还设置了一些信息属性:服务器返回的消息存储为ehlo_resp属性,根据服务器是否支持 ESMTP 将does_esmtp设置为 true 或 false,并且esmtp_features将是一个包含该服务器 SMTP 服务 extensions 的字典。支持及其参数(如果有)。

除非您希望在发送邮件之前使用has_extn(),否则不必显式调用此方法。必要时它将由sendmail()隐式调用。

  • SMTP. ehlo_or_helo_if_needed ( )

    • 如果此会话之前没有EHLOHELO命令,则此方法调用ehlo()和/或helo()。它首先try ESMTP EHLO
  • SMTPHeloError

    • 服务器未正确回复HELO问候。
  • SMTP. has_extn(* name *)

    • 如果服务器返回的 SMTP 服务 extensions 中有* name *,则返回True,否则返回False。大小写被忽略。
  • SMTP. verify(地址)

    • 使用 SMTP VRFY检查此服务器上地址的有效性。如果用户地址有效,则返回一个由代码 250 和完整的 RFC 822地址(包括人名)组成的 Tuples。否则,返回 SMTP 错误代码 400 或更高以及错误字符串。

Note

许多站点禁用 SMTP VRFY来阻止垃圾邮件发送者。

  • SMTP. login(* user password **,* initial_response_ok = True *)

    • 登录需要身份验证的 SMTP 服务器。参数是用于验证的用户名和密码。如果此会话没有先前的EHLOHELO命令,则此方法首先try ESMTP EHLO。如果身份验证成功,此方法将正常返回,或者可能引发以下异常:
  • SMTPHeloError

如果smtplib支持的每种身份验证方法被公布为服务器支持,则依次try。有关支持的身份验证方法的列表,请参见auth()。 * initial_response_ok *传递给auth()

可选关键字参数* initial_response_ok *指定对于支持它的身份验证方法,是否可以与AUTH命令一起发送 RFC 4954中指定的“初始响应”,而不是要求质询/响应。

在版本 3.5 中更改:可能引发SMTPNotSupportedError,并添加了* initial_response_ok *参数。

  • SMTP. auth(机制,* authobject **,* initial_response_ok = True *)
    • 发出用于指定身份验证机制SMTP AUTH命令,并pass* authobject *处理质询响应。

“机制”指定将哪种身份验证机制用作AUTH命令的参数;有效值是esmtp_featuresauth元素中列出的值。

  • authobject *必须是带有可选单个参数的可调用对象:

Note

数据= authobject(挑战=无)

如果可选关键字参数* initial_response_ok 为 true,则authobject()将首先被调用而没有参数。它可以返回 RFC 4954“初始响应” ASCII str,它将使用AUTH命令进行编码和发送,如下所示。如果authobject()不支持初始响应(例如,因为它需要质询),则在使用challenge=None调用时应返回None。如果 initial_response_ok *为 false,则不会先使用None调用authobject()

如果初始响应检查返回None,或者* initial_response_ok 为 false,则将调用authobject()来处理服务器的质询响应;传递给它的 challenge *参数是bytes。它应该返回 ASCII str * data *,它将被 base64 编码并发送到服务器。

SMTP类为CRAM-MD5PLAINLOGIN机制提供authobjects;它们分别命名为SMTP.auth_cram_md5SMTP.auth_plainSMTP.auth_login。它们都要求将SMTP实例的userpassword属性设置为适当的值。

用户代码通常不需要直接调用auth,而可以调用login()方法,该方法将按列出的 Sequences 依次try上述每种机制。公开auth以便于实现smtplib不直接(或尚未)支持的身份验证方法。

3.5 版中的新Function。

  • SMTP. starttls(* keyfile = None certfile = None context = None *)
    • 将 SMTP 连接置于 TLS(传输层安全性)模式下。随后的所有 SMTP 命令将被加密。然后,您应该再次致电ehlo()

如果提供了* keyfile certfile *,它们将用于创建ssl.SSLContext

可选的* context 参数是ssl.SSLContext对象;这是使用密钥文件和证书文件的替代方法,并且如果指定了 keyfile certfile *都应为None

如果此会话没有先前的EHLOHELO命令,则此方法首先try ESMTP EHLO

从 3.6 版开始不推荐使用:* keyfile certfile 不再推荐使用 context *。请改用ssl.SSLContext.load_cert_chain(),或让ssl.create_default_context()为您选择系统的受信任 CA 证书。

在版本 3.3 中更改:添加了* context *。

在版本 3.4 中进行了更改:该方法现在支持使用SSLContext.check_hostname和* Server Name Indicator *(请参阅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()等低级方法来发送邮件.)

Note

  • from_addr to_addrs *参数用于构造传输代理使用的消息信封。 sendmail不会以任何方式修改邮件头。
  • msg *可以是包含 ASCII 范围内字符的字符串,也可以是字节字符串。使用 ascii 编解码器将字符串编码为字节,并将单独的\r\n字符转换为\r\n字符。字节字符串未修改。

如果此会话没有先前的EHLOHELO命令,则此方法首先try ESMTP EHLO。如果服务器使用 ESMTP,则将向其传递邮件大小和每个指定的选项(如果该选项在服务器发布的Function集中)。如果EHLO失败,将tryHELO并抑制 ESMTP 选项。

如果至少一个收件人接受了该邮件,则此方法将正常返回。否则会引发异常。也就是说,如果此方法未引发异常,则应该有人收到您的邮件。如果此方法没有引发异常,它将返回一个字典,其中每个拒绝的接收者都有一个条目。每个条目都包含一个 SMTP 错误代码的 Tuples 以及服务器发送的附带错误消息。

如果SMTPUTF8包含在* mail_options 中,并且服务器支持它,则 from_addr to_addrs *可能包含非 ASCII 字符。

此方法可能会引发以下异常:

  • SMTPRecipientsRefused

    • 所有收件人均被拒绝。没有人收到邮件。异常对象的recipients属性是一本字典,其中包含有关被拒绝的收件人的信息(例如,当至少一个收件人被接受时返回的字典)。

    • 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 =()*)

如果* from_addr None to_addrs None,则send_message用从 RFC 5322中指定的从 msg 头中提取的地址填充这些参数: from_addr 设置为 Sender 字段(如果存在),并且否则为 From 字段。 * to_addrs 组合 msg To Cc Bcc 字段的值(如果有)。如果消息中仅出现一组 Resent- Headers,则常规 Headers 将被忽略,而使用 Resent- Headers 代替。如果邮件包含多个* Resent- Headers 集,则会引发ValueError,因为无法明确检测到最新的 Resent- *Headers 集。

send_message使用BytesGenerator并将\r\n作为* linesep 序列化 msg ,并调用sendmail()传输结果消息。无论 from_addr to_addrs 的值如何,send_message都不会传输 msg 中可能出现的任何 Bcc Resent-Bcc Headers。如果 from_addr to_addrs 中的任何地址包含非 ASCII 字符,并且服务器未宣传SMTPUTF8支持,则会引发SMTPNotSupported错误。否则,将Message与其policy的克隆(其utf8属性设置为True)进行序列化,并将SMTPUTF8BODY=8BITMIME添加到 mail_options *。

3.2 版中的新Function。

版本 3.5 中的新Function:支持国际化地址(SMTPUTF8)。

  • SMTP. quit ( )
    • 终止 SMTP 会话并关闭连接。返回 SMTP QUIT命令的结果。

还支持与标准 SMTP/ESMTP 命令HELPRSETNOOPMAILRCPTDATA对应的低级方法。通常,这些不需要直接调用,因此这里没有记录。有关详细信息,请查阅模块代码。

SMTP Example

本示例提示用户 Importing 邮件信封中所需的地址(“收件人”和“发件人”地址)以及要传递的邮件。请注意,要包含在消息中的 Headers 必须包含在 Importing 的消息中;本示例不对 RFC 822Headers 进行任何处理。特别是,“收件人”和“发件人”地址必须明确包含在消息头中。

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()

Note

通常,您将需要使用email软件包的Function来构造电子邮件,然后可以passsend_message()发送该电子邮件;参见email: Examples