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操作的完整系列的方法。如果给出了可选的主机和端口参数,则在初始化期间使用这些参数调用SMTPconnect()
方法。如果指定,则在HELO / EHLO命令中将local_hostname用作本地主机的FQDN。否则,使用socket.getfqdn()
找到本地主机名。如果connect()
调用返回除成功代码以外的任何内容,则会引发SMTPConnectError
。可选的timeout参数指定阻塞操作(如连接尝试)的超时(以秒为单位)(如果未指定,将使用全局默认超时设置)。如果超时到期,则会引发socket.timeout
。可选的source_address参数允许绑定到具有多个网络接口和/或某个特定源TCP端口的机器中的某个特定源地址。它需要一个2元组(主机,端口),套接字绑定为其源地址,然后连接。如果省略(或者如果主机或端口分别为''
和/或0),则将使用操作系统默认行为。对于正常使用,您只需要初始化/ connect,
sendmail()
和quit()
方法。下面包含一个例子。SMTP
类支持with
语句。当这样使用时,当with
语句退出时,会自动发出SMTPQUIT
命令。例如。:>>> 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.
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验证失败。很可能服务器不接受提供的用户名/密码组合。
也可以看看
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 theehlo_resp
attribute,does_esmtp
is set to true or false depending on whether the server supports ESMTP, andesmtp_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
()¶ 如果之前没有先前的
EHLO
或HELO
命令,则此方法调用ehlo()
和或helo()
它首先尝试ESMTPEHLO
。SMTPHeloError
- 服务器未正确回复
HELO
问候语。
-
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)¶ 针对指定的认证机制发出
SMTP
AUTH
命令,并通过authobject处理质询响应。机制指定要将哪个认证机制用作
AUTH
命令的参数;有效值是在esmtp_features
的auth
元素中列出的有效值。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-MD5
,PLAIN
和LOGIN
提供authobjects
机制;它们分别命名为SMTP.auth_cram_md5
,SMTP.auth_plain
和SMTP.auth_login
。它们都要求将SMTP
实例的user
和password
属性设置为适当的值。用户代码通常不需要直接调用
auth
,而是可以调用login()
方法,它将按照列出的顺序依次尝试上述每个机制。auth
是为了方便实现尚未(或尚未)由smtplib
直接支持的身份验证方法。版本3.5中的新功能。
-
SMTP.
starttls
(keyfile=None, certfile=None, context=None)¶ 将SMTP连接设置为TLS(传输层安全)模式。随后的所有SMTP命令将被加密。然后,您应再次调用
ehlo()
。如果提供密钥文件和certfile,则将它们传递给
socket
模块的ssl()
函数。可选的上下文参数是
ssl.SSLContext
对象;这是使用密钥文件和certfile的替代方法,如果指定keyfile和certfile应为None。如果先前没有先前
EHLO
或HELO
命令此会话,则此方法首先尝试ESMTPEHLO
。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选项列表(例如8bitmime
) mail_options。应该与所有RCPT
命令一起使用的ESMTP选项(例如DSN
命令)可以作为rcpt_options传递。(如果您需要对不同的收件人使用不同的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_addr可能包含非ASCII字符。该方法可以引入以下例外:
SMTPRecipientsRefused
- 所有收件人都被拒绝。没有人收到邮件。异常对象的
recipients
属性是包含有关被拒绝的收件人(如至少一个收件人被接受时返回的收件人)的信息的字典。 SMTPHeloError
- 服务器未正确回复
HELO
问候语。 SMTPSenderRefused
- 服务器不接受from_addr。
SMTPDataError
- 服务器回复了意外的错误代码(除了收件人拒绝)。
SMTPNotSupportedError
SMTPUTF8
在mail_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()
相同的含义,除了msg是Message
对象。If from_addr is
None
or to_addrs isNone
,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的至,Cc和Bcc字段的值。如果消息中只出现一组Resent - *标头,则会忽略常规标头,而改用Resent - *标头。如果消息包含多个Resent - *头,则会引发一个ValueError
,因为没有办法明确检测最近的Resent - 标头。send_message
使用BytesGenerator
以\r\n
作为linesep来序列化msg调用sendmail()
发送生成的消息。无论from_addr和to_addrs的值,send_message
不传送任何Bcc或Resent-Bcc 可能会出现在msg中的标头。如果from_addr和to_addrs中的任何地址包含非ASCII字符,并且服务器不通告SMTPUTF8
支持,则SMTPNotSupported
Otherwise theMessage
is serialized with a clone of itspolicy
with theutf8
attribute set toTrue
, andSMTPUTF8
andBODY=8BITMIME
are added to mail_options.版本3.2中的新功能。
版本3.5中的新功能:支持国际化地址(
SMTPUTF8
)。
-
SMTP.
quit
()¶ 终止SMTP会话并关闭连接。返回SMTP
QUIT
命令的结果。
对应于标准SMTP / ESMTP命令HELP
,RSET
,NOOP
,MAIL
,RCPT
和DATA
。通常这些不需要直接调用,因此在这里没有记录。有关详细信息,请参阅模块代码。
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。