Skip to main content

21.18. smtpd — SMTP服务器

源代码: Lib/smtpd.py


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

存在几个服务器实现;一个是通用的无用的实现,可以被覆盖,而另外两个提供特定的邮件发送策略。

此外,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 都应该是 (主机,端口) 元组。对象从 asyncore.dispatcher 继承,因此将在实例化时将自身插入到 asyncore 的事件循环中。

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

map 是用于连接的套接字映射(最初为空的字典是一个合适的值)。如果未指定,则使用 asyncore 全局套接字映射。

enable_SMTPUTF8 确定是否应该启用 SMTPUTF8 扩展(如 RFC 6531 中定义的)。默认值为 False。当 TrueSMTPUTF8 被接受作为 MAIL 命令的参数并且当存在时被传递到 kwargs['mail_options'] 列表中的 process_message()decode_dataenable_SMTPUTF8 不能同时设置为 True

decode_data 指定是否应使用UTF-8解码SMTP事务的数据部分。当 decode_dataFalse (默认值)时,服务器通告 8BITMIME 扩展(RFC 6152),接受 BODY=8BITMIME 参数给 MAIL 命令,当存在时将其传递给 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 constructor关键字设置为 True,则 data 参数将是一个unicode字符串。如果设置为 False,它将是一个字节对象。

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

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 时,kwargs 参数为 process_message()

在 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配置知道地址,在这种情况下它将通过邮递员处理。注意,运行这个有一个很好的机会,使你成为一个开放的中继,所以请小心。

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 指定是否应使用UTF-8解码SMTP事务的数据部分。默认值为 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

在其“帮助”中保存由客户端发送的包含问候语的字符串。

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

不采取任何行动。

放弃

干净地关闭连接。

邮件

接受“MAIL FROM:”语法,并将提供的地址存储为 mailfrom。在扩展命令模式下,接受 RFC 1870 SIZE属性,并根据 data_size_limit 的值适当响应。

RCPT

接受“RCPT TO:”语法,并将提供的地址存储在 rcpttos 列表中。

RSET

重置 mailfromrcpttosreceived_data,但不是问候语。

数据

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

帮帮我

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

VRFY

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

EXPN

报告命令未实现。