21.18. smtpd — SMTP 服务器

源代码: Lib/smtpd.py


该模块提供了几个类来实现 SMTP (电子邮件)服务器。

也參考

The aiosmtpd package is a recommended replacement for this module. It is based on asyncio and provides a more straightforward API. smtpd should be considered deprecated.

有几个服务器的实现;一个是通用的无为实现,可以被重写,而另外两个则提供特定的邮件发送策略。

此外, SMTPChannel 可以被扩展以实现与 SMTP 客户端非常具体的交互行为。

该代码支持 RFC 5321 ,加上 RFC 1870 SIZE和 RFC 6531 SMTPUTF8 扩展。

21.18.1. SMTPServer 对象

class smtpd.SMTPServer(localaddr, remoteaddr, data_size_limit=33554432, map=None, enable_SMTPUTF8=False, decode_data=False)

新建一个 SMTPServer 对象,它会绑定到本机地址 localaddr。 它将把 remoteaddr 当作上游 SMTP 中继器。 localaddrremoteaddr 都应当是 (host, port) 元组。 该对象继承自 asyncore.dispatcher,因而会在实例化时将自己插入到 asyncore 的事件循环。

data_size_limit 指定将在 DATA 命令中被接受的最大字节数。 值为 None0 表示无限制。

map 是用于连接的套接字映射(初始为空的字典是适当的值)。 如果未指定则会使用 asyncore 全局套接字映射。

enable_SMTPUTF8 决定是否应当启用 SMTPUTF8 扩展(如 RFC 6531 所定义的。 默认值为 False。 当设为 True 时,会接受 SMTPUTF8 作为 MAIL 命令的形参并在被提供时将其传给 kwargs['mail_options'] 列表中的 process_message()decode_dataenable_SMTPUTF8 不可同时被设为 True

decode_data 指明 SMTP 事务的数据部分是否应当使用 UTF-8 来解码。 当 decode_dataFalse 时(默认值),服务器会声明 8BITMIME 扩展 (RFC 6152),接受来自 MAIL 命令的 BODY=8BITMIME 形参,并在该形参存在时将其传给 kwargs['mail_options'] 列表中的 process_message() 方法。 decode_dataenable_SMTPUTF8 不可同时被设为 True

process_message(peer, mailfrom, rcpttos, data, **kwargs)

引发 NotImplementedError 异常。 请在子类中重载此方法以实际运用此消息。 在构造器中作为 remoteaddr 传入的任何东西都可以 _remoteaddr 属性的形式来访问。 peer 是远程主机的地址,mailfrom 是封包的发送方,rcpttos 是封包的接收方而 data 是包含电子邮件内容的字符串(应该为 RFC 5321 格式)。

如果构造器关键字参数 decode_data 被设为 True,则 data 参数将为 Unicode 字符串。 如果被设为 False,则将为字节串对象。

kwargs 是包含附加信息的字典。 如果给出 decode_data=True 作为初始参数则该字典为空,否则它会包含以下的键:

mail_options:

MAIL 命令所接收的所有参数组成的列表 (其元素为大写形式的字符串;例如: ['BODY=8BITMIME', 'SMTPUTF8'])。

rcpt_options:

mail_options 类似但是针对 RCPT 命令。 目前不支持任何 RCPT TO 选项,因此其值将总是为空列表。

process_message 的实现应当使用 **kwargs 签名来接收任意关键字参数,因为未来的增强特性可能会向 kwargs 字典添加新键。

返回 None 以请求一个正常的 250 Ok 响应;在其他情况下则以 RFC 5321 格式返回所需的响应字符串。

channel_class

重载这个子类以使用自定义的 SMTPChannel 来管理 SMTP 客户端。

3.4 版新加入: map 构造器参数。

3.5 版更變: localaddrremoteaddr 现在可以包含 IPv6 地址。

3.5 版新加入: decode_dataenable_SMTPUTF8 构造器形参,以及当 decode_dataFalse 时传给 process_message()kwargs 形参。

3.6 版更變: decode_data 现在默认为 False

21.18.2. DebuggingServer 对象

class smtpd.DebuggingServer(localaddr, remoteaddr)

创建一个新的调试服务器。 参数是针对每个 SMTPServer。 消息将被丢弃,并在 stdout 上打印出来。

21.18.3. PureProxy对象

class smtpd.PureProxy(localaddr, remoteaddr)

创建一个新的纯代理服务器。 参数是针对每个 SMTPServer。 一切都将被转发到 remoteaddr。 请注意运行此对象有很大的机会令你成为一个开放的中继站,所以需要小心。

21.18.4. MailmanProxy 对象

class smtpd.MailmanProxy(localaddr, remoteaddr)

创建一个新的纯代理服务器。 参数是针对每个 SMTPServer。 一切都将被转发到 remoteaddr,除非本地 mailman 配置知道另一个地址,在那种情况下它将由 mailman 来处理。 请注意运行此对象有很大的机会令你成为一个开放的中继站,所以需要小心。

21.18.5. SMTPChannel 对象

class smtpd.SMTPChannel(server, conn, addr, data_size_limit=33554432, map=None, enable_SMTPUTF8=False, decode_data=False)

创建一个新的 SMTPChannel 对象,该对象会管理服务器和单个 SMTP 客户端之间的通信。

connaddr 是针对下述的每个实例变量。

data_size_limit 指定将在 DATA 命令中被接受的最大字节数。 值为 None0 表示无限制。

enable_SMTPUTF8 确定 SMTPUTF8 扩展 (如 RFC 6531 所定义的) 是否应当被启用。 默认值为 Falsedecode_dataenable_SMTPUTF8 不能被同时设为 True

可以在 map 中指定一个字典以避免使用全局套接字映射。

decode_data 指明 SMTP 事务的数据部分是否应当使用 UTF-8 来解码。 默认值为 Falsedecode_dataenable_SMTPUTF8 不能被同时设为 True

要使用自定义的 SMTPChannel 实现你必须重载你的 SMTPServerSMTPServer.channel_class

3.5 版更變: 添加了 decode_dataenable_SMTPUTF8 形参。

3.6 版更變: decode_data 现在默认为 False

SMTPChannel 具有下列实例变量:

smtp_server

存放生成此通道的 SMTPServer

conn

存放连接到客户端的套接字对象。

addr

存放客户端的地址,socket.accept 所返回的第二个值。

received_lines

存放从客户端接收的行字符串列表 (使用 UTF-8 解码)。 所有行的 "\r\n" 行结束符都会被转写为 "\n"

smtp_state

存放通道的当前状态。 其初始值将为 COMMAND 而在客户端发送 「DATA」 行后将为 DATA

seen_greeting

存放包含客户端在其 「HELO」 中发送的问候信息的字符串。

mailfrom

存放包含客户端在 「MAIL FROM:」 中标识的地址的字符串。

rcpttos

存放包含客户端在 「RCPT TO:」 行中标识的地址的字符串。

received_data

存放客户端在 DATA 状态期间发送的所有数据的字符串,直至但不包括末尾的 "\r\n.\r\n"

fqdn

存放由 socket.getfqdn() 所返回的服务器完整限定域名。

peer

存放由 conn.getpeername() 所返回的客户端对等方名称,其中 connconn

SMTPChannel 在接收到来自客户端的命令行时会通过发起调用名为 smtp_<command> 的方法来进行操作。 在基类 SMTPChannel 中具有用于处理下列命令(并对他们作出适当反应)的方法:

命令

所采取的行动

HELO

接受来自客户端的问候语,并将其存储在 seen_greeting 中。将服务器设置为基本命令模式。

EHLO

接受来自客户的问候并将其存储在 seen_greeting 中。将服务器设置为扩展命令模式。

NOOP

不采取任何措施。

QUIT

干净地关闭连接。

MAIL

接受 「MAIL FROM:」 句法并将所提供的地址保存为 mailfrom。 在扩展命令模式下,还接受 RFC 1870 SIZE 属性并根据 data_size_limit 的值作出适当返回。

RCPT

接受 「RCPT TO:」 句法并将所提供的地址保存在 rcpttos 列表中。

RSET

重置 mailfrom, rcpttos, 和 received_data ,但不重置问候语。

DATA

将内部状态设为 DATA 并将来自客户端的剩余行保存在 received_data 中直至接收到终止符 "\r\n.\r\n"

HELP

返回有关命令语法的最少信息

VRFY

返回代码252(服务器不知道该地址是否有效)

EXPN

报告该命令未实现。