20.12. smtplib-SMTP 协议 Client 端

源代码: Lib/smtplib.py


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

    • class * smtplib. SMTP([* host * [,* port * [,* local_hostname * [,* timeout *]]]])
    • SMTP实例封装了 SMTP 连接。它具有支持 SMTP 和 ESMTP 操作的全部Function的方法。如果给出了可选的主机和端口参数,则在初始化期间将使用这些参数调用 SMTP connect()方法。如果指定,* local_hostname 用作 HELO/EHLO 命令中 localhost 的 FQDN。否则,使用socket.getfqdn()找到 localhost 名。如果connect()调用返回成功代码以外的任何内容,则会引发SMTPConnectError。可选的 timeout *参数以秒为单位指定用于阻止诸如连接try之类的操作的超时(如果未指定,将使用全局默认超时设置)。如果超时到期,则socket.timeout被提高。

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

在 2.6 版中进行了更改:添加了“超时”。

    • class * smtplib. SMTP_SSL([* host * [,* port * [,* local_hostname * [,* keyfile * [,* certfile * [,* timeout *]]]]]]]))
    • SMTP_SSL实例的行为与SMTP实例完全相同。 SMTP_SSL应该用于从连接开始就需要 SSL 且不适合使用starttls()的情况。如果未指定* host ,则使用 localhost。如果Ellipsis port *,则使用标准的 SMTP-over-SSL 端口(465)。 * local_hostname *具有与SMTP类相同的含义。 * keyfile certfile 也是可选的,它们可以包含用于 SSL 连接的 PEM 格式的私钥和证书链文件。可选的 timeout *参数以秒为单位指定用于阻止诸如连接try之类的操作的超时(如果未指定,将使用全局默认超时设置)。如果超时到期,则socket.timeout升高。

2.6 版的新Function。

    • class * smtplib. LMTP([* host * [,* port * [,* local_hostname *]]])
    • LMTP 协议与 ESMTP 非常相似,它很大程度上基于标准的 SMTPClient 端。对于 LMTP,通常使用 Unix 套接字,因此我们的connect()方法必须支持该套接字以及常规的 host:port 服务器。 * local_hostname 具有与SMTP类相同的含义。要指定 Unix 套接字,必须为 host *使用绝对路径,以'/'开头。

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

2.6 版的新Function。

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

  • exception smtplib. SMTPException

    • 此模块提供的所有其他异常的基本异常类。
  • 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. SMTPAuthenticationError

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

See also

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

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

  • RFC 1869-SMTP 服务扩展

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

20.12.1. SMTP 对象

SMTP实例具有以下方法:

  • SMTP. set_debuglevel(级别)

    • 设置调试输出级别。 * level *的值为 true 会导致连接的调试消息以及发送到服务器和从服务器接收的所有消息。
  • SMTP. docmd(* cmd * [,* argstring *])

    • 向服务器发送命令* cmd 。可选参数 argstring *只是连接到命令,用空格分隔。

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

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

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

  • SMTP. connect([* host * [,* port *]])

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

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

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

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

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

  • SMTP. ehlo_or_helo_if_needed ( )

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

    • 服务器未正确回复HELO问候。

2.6 版的新Function。

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

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

  • SMTP. starttls([* * keyfile * [,* certfile *]])

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

如果提供了* keyfile certfile *,它们将被传递到socket模块的ssl()函数。

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

在 2.6 版中进行了更改。

在 2.6 版中进行了更改。

  • RuntimeError

    • 您的 Python 解释器不提供 SSL/TLS 支持。
  • 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 *参数用于构造传输代理使用的消息信封。 SMTP不会以任何方式修改邮件头。

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

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

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

  • SMTPRecipientsRefused

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

    • SMTPHeloError

      • 服务器未正确回复HELO问候。
    • SMTPSenderRefused

      • 服务器不接受* from_addr *。
    • SMTPDataError

      • 服务器回复了意外的错误代码(拒绝接收者除外)。

除非另有说明,否则即使出现异常也将打开连接。

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

在 2.6 版中进行了更改:返回一个值。

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

20.12.2. SMTP 范例

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

import smtplib

def prompt(prompt):
    return raw_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 1:
    try:
        line = raw_input()
    except EOFError:
        break
    if not line:
        break
    msg = msg + line

print "Message length is " + repr(len(msg))

server = smtplib.SMTP('localhost')
server.set_debuglevel(1)
server.sendmail(fromaddr, toaddrs, msg)
server.quit()

Note

通常,您将需要使用email软件包的Function来构造电子邮件,然后可以将其转换为字符串并passsendmail()发送;参见email: Examples