20.12. smtplib — SMTP 协议客户端 — Python 文档

来自菜鸟教程
Python/docs/2.7/library/smtplib
跳转至:导航、​搜索

20.12. smtplib — SMTP 协议客户端

源代码: :source:`Lib/smtplib.py`



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

class smtplib.SMTP([host[, port[, local_hostname[, timeout]]]])

SMTP 实例封装了一个 SMTP 连接。 它的方法支持完整的 SMTP 和 ESMTP 操作。 如果给出了可选的主机和端口参数,则在初始化期间使用这些参数调用 SMTP connect() 方法。 如果指定,local_hostname 用作 HELO/EHLO 命令中本地主机的 FQDN。 否则,使用 socket.getfqdn() 找到本地主机名。 如果 connect() 调用返回成功代码以外的任何内容,则会引发 SMTPConnectError。 可选的 timeout 参数指定阻塞操作(如连接尝试)的超时(以秒为单位)(如果未指定,将使用全局默认超时设置)。 如果超时到期,则会引发 socket.timeout

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

2.6 版更改:添加了 timeout

class smtplib.SMTP_SSL([host[, port[, local_hostname[, keyfile[, certfile[, timeout]]]]]])

SMTP_SSL 实例的行为与 SMTP 的实例完全相同。 SMTP_SSL 应该用于从连接开始就需要 SSL 并且使用 starttls() 不合适的情况。 如果未指定 host,则使用本地主机。 如果省略 port,则使用标准的 SMTP-over-SSL 端口 (465)。 local_hostnameSMTP 类具有相同的含义。 keyfilecertfile 也是可选的,可以包含用于 SSL 连接的 PEM 格式的私钥和证书链文件。 可选的 timeout 参数指定阻塞操作(如连接尝试)的超时(以秒为单位)(如果未指定,将使用全局默认超时设置)。 如果超时到期,则会引发 socket.timeout

2.6 版中的新功能。

class smtplib.LMTP([host[, port[, local_hostname]]])

LMTP 协议与 ESMTP 非常相似,很大程度上基于标准 SMTP 客户端。 为 LMTP 使用 Unix 套接字是很常见的,所以我们的 connect() 方法必须支持它以及常规的主机:端口服务器。 local_hostnameSMTP 类具有相同的含义。 要指定 Unix 套接字,您必须对 host 使用绝对路径,以“/”开头。

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

2.6 版中的新功能。

还定义了一个不错的例外选择:

exception smtplib.SMTPException
此模块提供的所有其他异常的基本异常类。
exception smtplib.SMTPServerDisconnected
当服务器意外断开连接,或者在连接到服务器之前尝试使用 SMTP 实例时,会引发此异常。
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.SMTPAuthenticationError
SMTP 身份验证出错。 很可能服务器不接受提供的用户名/密码组合。

也可以看看

RFC 821 - 简单邮件传输协议
SMTP 的协议定义。 本文档涵盖了 SMTP 的模型、操作过程和协议详细信息。
RFC 1869 - SMTP 服务扩展
SMTP 的 ESMTP 扩展的定义。 这描述了一个使用新命令扩展 SMTP 的框架,支持动态发现服务器提供的命令,并定义了一些额外的命令。


20.12.1. SMTP 对象

SMTP 实例具有以下方法:

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

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

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

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

如果在等待回复时与服务器的连接丢失,将引发 SMTPServerDisconnected

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

使用 HELO 向 SMTP 服务器表明您自己。 hostname 参数默认为本地主机的完全限定域名。 服务器返回的消息存储为对象的 helo_resp 属性。

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

SMTP.ehlo([hostname])

使用 EHLO 向 ESMTP 服务器表明您自己。 hostname 参数默认为本地主机的完全限定域名。 检查 ESMTP 选项的响应并存储它们以供 has_extn() 使用。 还设置了几个信息属性:服务器返回的消息存储为ehlo_resp属性,does_esmtp根据服务器是否支持ESMTP设置为true或false,以及esmtp_features ] 将是一个字典,其中包含此服务器支持的 SMTP 服务扩展名及其参数(如果有)。

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

SMTP.ehlo_or_helo_if_needed()

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

SMTPHeloError

服务器没有正确回复 HELO 问候语。

2.6 版中的新功能。

SMTP.has_extn(name)
如果 name 在服务器返回的 SMTP 服务扩展集中,则返回 True,否则返回 False。 大小写被忽略。
SMTP.verify(address)

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

笔记

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

SMTP.login(user, password)
登录需要身份验证的 SMTP 服务器。 参数是要进行身份验证的用户名和密码。 如果之前没有 EHLOHELO 命令此会话,则此方法首先尝试 ESMTP EHLO。 如果身份验证成功,此方法将正常返回,或者可能引发以下异常:
SMTPHeloError
服务器没有正确回复 HELO 问候语。
SMTPAuthenticationError
服务器不接受用户名/密码组合。
SMTPException
未找到合适的身份验证方法。
SMTP.starttls([keyfile[, certfile]])

将 SMTP 连接置于 TLS(传输层安全)模式。 随后的所有 SMTP 命令都将被加密。 然后您应该再次调用 ehlo()

如果提供了 keyfilecertfile,它们将被传递给 socket 模块的 ssl() 函数。

如果之前没有 EHLOHELO 命令此会话,则此方法首先尝试 ESMTP EHLO

在 2.6 版中更改。

SMTPHeloError

服务器没有正确回复 HELO 问候语。

SMTPException

服务器不支持 STARTTLS 扩展。

在 2.6 版中更改。

RuntimeError

您的 Python 解释器不支持 SSL/TLS。

SMTP.sendmail(from_addr, to_addrs, msg[, mail_options, rcpt_options])

发邮件。 所需的参数是 RFC 822 来自地址字符串,RFC 822 到地址字符串列表(一个裸字符串将被视为具有 1 个地址的列表)和消息字符串。 调用者可以将要在 MAIL FROM 命令中使用的 ESMTP 选项列表(例如 8bitmime)作为 mail_options 传递。 应该与所有 RCPT 命令一起使用的 ESMTP 选项(例如 DSN 命令)可以作为 rcpt_options 传递。 (如果您需要对不同的收件人使用不同的 ESMTP 选项,则必须使用 mail()rcpt()data() 等低级方法来发送邮件。)

笔记

from_addrto_addrs 参数用于构造传输代理使用的消息信封。 SMTP 不会以任何方式修改邮件头。

如果之前没有 EHLOHELO 命令此会话,则此方法首先尝试 ESMTP EHLO。 如果服务器执行 ESMTP,消息大小和每个指定的选项将传递给它(如果该选项在服务器通告的功能集中)。 如果 EHLO 失败,将尝试 HELO 并抑制 ESMTP 选项。

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

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

SMTPRecipientsRefused

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

SMTPHeloError

服务器没有正确回复 HELO 问候语。

SMTPSenderRefused

服务器不接受 from_addr

SMTPDataError

服务器回复了一个意外的错误代码(除了收件人的拒绝)。

除非另有说明,否则即使引发异常,连接也会打开。

SMTP.quit()

终止 SMTP 会话并关闭连接。 返回 SMTP QUIT 命令的结果。

2.6 版改动:返回一个值。

对应于标准 SMTP/ESMTP 命令的低级方法 HELPRSETNOOPMAILRCPTDATA 也支持。 通常这些不需要直接调用,所以这里没有记录。 详情请查阅模块代码。


20.12.2. SMTP 示例

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

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

笔记

通常,您会希望使用 email 包的功能来构建电子邮件,然后您可以将其转换为字符串并通过 sendmail() 发送; 请参阅 电子邮件:示例