21.17. smtplib - SMTP协议客户端

源代码: Lib / smtplib.py

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

class smtplib.SMTP(host='', port=0, local_hostname=None, [timeout, ]source_address=None)

SMTP实例封装了SMTP连接。它具有支持SMTP和ESMTP操作的完整系列的方法。如果给出了可选的主机和端口参数,则在初始化期间使用这些参数调用SMTP connect()方法。如果指定,则在HELO / EHLO命令中将local_hostname用作本地主机的FQDN。否则,使用socket.getfqdn()找到本地主机名。如果connect()调用返回除成功代码以外的任何内容,则会引发SMTPConnectError可选的timeout参数指定阻塞操作(如连接尝试)的超时(以秒为单位)(如果未指定,将使用全局默认超时设置)。如果超时到期,则会引发socket.timeout可选的source_address参数允许绑定到具有多个网络接口和/或某个特定源TCP端口的机器中的某个特定源地址。它需要一个2元组(主机,端口),套接字绑定为其源地址,然后连接。如果省略(或者如果主机或端口分别为''和/或0),则将使用操作系统默认行为。

对于正常使用,您只需要初始化/ connect,sendmail()quit()方法。下面包含一个例子。

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

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

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

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

版本3.5中的新功能:现在支持SMTPUTF8扩展( 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,则使用本地主机。如果port为零,则使用标准的SMTP over SSL端口(465)。可选参数local_hostname超时source_address的含义与在SMTP类中的含义相同。上下文也是可选的,可以包含SSLContext并允许配置安全连接的各个方面。有关最佳做法,请参阅Security considerations

键文件certfile上下文的旧式替代,可指向用于SSL连接的PEM格式的私钥和证书链文件。

Changed in version 3.3: context was added.

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

在版本3.4中更改:此类现在支持使用ssl.SSLContext.check_hostname服务器名称指示(请参阅ssl.HAS_SNI)。

class smtplib.LMTP(host='', port=LMTP_PORT, local_hostname=None, source_address=None)

LMTP协议非常类似于ESMTP,主要基于标准的SMTP客户端。对于LMTP使用Unix套接字是很常见的,所以我们的connect()方法必须支持常规主机:port server。可选参数local_hostname和source_address的含义与在SMTP类中的含义相同。要指定Unix套接字,必须使用host的绝对路径,以'/'开头。

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

一个很好的异常选择也被定义:

exception smtplib.SMTPException

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

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

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.SMTPNotSupportedError

尝试的命令或选项不受服务器支持。

版本3.5中的新功能。

exception smtplib.SMTPAuthenticationError

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

也可以看看

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

21.17.1. SMTP Objects

SMTP实例具有以下方法:

SMTP.set_debuglevel(level)

设置调试输出电平。对于级别,值为1或True会导致连接的调试消息以及发送到服务器和从服务器接收的所有消息。级别的值为2会导致这些消息带有时间戳。

在版本3.5中已更改:添加了调试级别2。

SMTP.docmd(cmd, args='')

向服务器发送命令cmd可选参数args简单地连接到命令,用空格分隔。

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

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

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

SMTP.connect(host='localhost', port=0)

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

SMTP.helo(name='')

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

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

SMTP.ehlo(name='')

使用EHLO向ESMTP服务器标识自己。hostname参数默认为本地主机的完全限定域名。检查ESMTP选项的响应,并将其存储以供has_extn()使用。Also sets several informational attributes: the message returned by the server is stored as the ehlo_resp attribute, does_esmtp is set to true or false depending on whether the server supports ESMTP, and esmtp_features will be a dictionary containing the names of the SMTP service extensions this server supports, and their parameters (if any).

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

SMTP.ehlo_or_helo_if_needed()

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

SMTPHeloError
服务器未正确回复HELO问候语。
SMTP.has_extn(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服务器。参数是要认证的用户名和密码。如果先前没有先前EHLOHELO命令此会话,则此方法首先尝试ESMTP EHLO如果身份验证成功,此方法将正常返回,或可能引发以下异常:

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)

针对指定的认证机制发出SMTP AUTH命令,并通过authobject处理质询响应。

机制指定要将哪个认证机制用作AUTH命令的参数;有效值是在esmtp_featuresauth元素中列出的有效值。

authobject必须是采用可选单参数的可调用对象:

data = authobject(challenge=None)

如果可选的关键字参数initial_response_ok为true,则将首先调用无参数的authobject()它可以返回将被编码并与AUTH命令一起发送的 RFC 4954“初始响应”字节,如下所示。如果authobject()不支持初始响应(例如,因为它需要一个挑战),当使用challenge=None调用时应该返回None。如果initial_response_ok为false,则authobject()不会先调用None。

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

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

用户代码通常不需要直接调用auth,而是可以调用login()方法,它将按照列出的顺序依次尝试上述每个机制。auth是为了方便实现尚未(或尚未)由smtplib直接支持的身份验证方法。

版本3.5中的新功能。

SMTP.starttls(keyfile=None, certfile=None, context=None)

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

如果提供密钥文件certfile,则将它们传递给socket模块的ssl()函数。

可选的上下文参数是ssl.SSLContext对象;这是使用密钥文件和certfile的替代方法,如果指定keyfilecertfile应为None。

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

SMTPHeloError
服务器未正确回复HELO问候语。
SMTPNotSupportedError
服务器不支持STARTTLS扩展。
RuntimeError
SSL / TLS支持不适用于您的Python解释器。

改变在3.3版本:加入 T0> 背景 T1>。

在版本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个地址的列表)和消息字符串。呼叫者可以传递在MAIL FROM命令中使用的ESMTP选项列表(例如8bitmimemail_options应该与所有RCPT命令一起使用的ESMTP选项(例如DSN命令)可以作为rcpt_options传递。(如果您需要对不同的收件人使用不同的ESMTP选项,则必须使用低级方法,例如mail()rcpt()data()发送消息。)

注意

from_addrto_addrs参数用于构造传输代理使用的消息包络。sendmail不以任何方式修改邮件标头。

msg可以是包含ASCII范围中的字符的字符串,也可以是字节字符串。使用ascii编解码器将字符串编码为字节,并将单个\r\n字符转换为\r\n字符。不修改字节字符串。

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

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

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

该方法可以引入以下例外:

SMTPRecipientsRefused
所有收件人都被拒绝。没有人收到邮件。异常对象的recipients属性是包含有关被拒绝的收件人(如至少一个收件人被接受时返回的收件人)的信息的字典。
SMTPHeloError
服务器未正确回复HELO问候语。
SMTPSenderRefused
服务器不接受from_addr
SMTPDataError
服务器回复了意外的错误代码(除了收件人拒绝)。
SMTPNotSupportedError
SMTPUTF8mail_options中给出,但服务器不支持。

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

在版本3.2中更改: msg可能是字节字符串。

在已指定SMTPUTF8的情况下,在版本3.5中更改了 SMTPUTF8支持,并且可能会出现SMTPNotSupportedError不支持它。

SMTP.send_message(msg, from_addr=None, to_addrs=None, mail_options=[], rcpt_options=[])

这是一种方便的方法,用于调用sendmail()和由email.message.Message对象表示的消息。参数具有与sendmail()相同的含义,除了msgMessage对象。

If from_addr is None or to_addrs is None, send_message fills those arguments with addresses extracted from the headers of msg as specified in RFC 5322: from_addr is set to the Sender field if it is present, and otherwise to the From field. to_adresses组合来自msg的CcBcc字段的值如果消息中只出现一组Resent - *标头,则会忽略常规标头,而改用Resent - *标头。如果消息包含多个Resent - *头,则会引发一个ValueError,因为没有办法明确检测最近的Resent - 标头。

send_message使用BytesGenerator\r\n作为linesep来序列化msg调用sendmail()发送生成的消息。无论from_addrto_addrs的值,send_message不传送任何BccResent-Bcc 可能会出现在msg中的标头。如果from_addrto_addrs中的任何地址包含非ASCII字符,并且服务器不通告SMTPUTF8支持,则SMTPNotSupportedOtherwise the Message is serialized with a clone of its policy with the utf8 attribute set to True, and SMTPUTF8 and BODY=8BITMIME are added to mail_options.

版本3.2中的新功能。

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

SMTP.quit()

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

对应于标准SMTP / ESMTP命令HELPRSETNOOPMAILRCPTDATA通常这些不需要直接调用,因此在这里没有记录。有关详细信息,请参阅模块代码。

21.17.2. SMTP Example

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

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

注意

一般来说,您会想要使用email套件的功能来构建电子邮件,然后您可以通过send_message()发送电子邮件;请参阅email: Examples