14.3. smtpd — SMTP 服务器
目的:包括用于实现SMTP服务器的类。
smtpd
模块包括用于构建简单邮件传输协议服务器的类。它是[smtplib
](pymotw.com/3/smtplib/index.html#mo...“ smtplib:简单邮件传输协议客户端”使用的协议的服务器端。 )。
邮件服务器基类
所有提供的示例服务器的基类是SMTPServer
。它处理与客户端的通信,接收传入的数据,并提供了一个方便的钩子,可以在消息完全可用后进行覆盖以对其进行处理。
构造函数参数是用于侦听连接的本地地址,也是应将代理消息传递到的远程地址。提供方法process_message()
作为挂钩,以被派生类覆盖。当完全接收到消息并给出以下参数时,将调用它:
peer
客户地址,一个包含IP和传入端口的元组。
mailfrom
邮件信封中的“发件人”信息,在邮件传递时由客户端提供给服务器。不一定在所有情况下都匹配
From
标题。
rcpttos
邮件信封中的收件人列表。同样,这并不总是与
To
标头匹配,尤其是在收件人被盲目抄写的情况下。
data
完整的RFC 5322消息正文
process_message()
的默认实现会引起NotImplementedError
。下一个示例定义一个子类,该子类重写用于打印有关接收到的消息的信息的方法。
smtpd_custom.py
import smtpd
import asyncore
class CustomSMTPServer(smtpd.SMTPServer):
def process_message(self, peer, mailfrom, rcpttos, data):
print('Receiving message from:', peer)
print('Message addressed from:', mailfrom)
print('Message addressed to :', rcpttos)
print('Message length :', len(data))
server = CustomSMTPServer(('127.0.0.1', 1025), None)
asyncore.loop()
SMTPServer
使用asyncore
,因此要运行服务器调用asyncore.loop()
。
需要一个客户端来演示服务器。可以是[smtplib
](pymotw.com/3/smtplib/index.html#mo...“ smtplib:简单邮件传输协议客户端。”)中的示例之一。适用于创建客户端以将数据发送到在端口1025上本地运行的测试服务器。
smtpd_senddata.py
import smtplib
import email.utils
from email.mime.text import MIMEText
# 创建消息
msg = MIMEText('This is the body of the message.')
msg['To'] = email.utils.formataddr(('Recipient',
'recipient@example.com'))
msg['From'] = email.utils.formataddr(('Author',
'author@example.com'))
msg['Subject'] = 'Simple test message'
server = smtplib.SMTP('127.0.0.1', 1025)
server.set_debuglevel(True) # 显示与服务器的通信
try:
server.sendmail('author@example.com',
['recipient@example.com'],
msg.as_string())
finally:
server.quit()
要测试程序,请在一个终端中运行smtpd_custom.py
,在另一终端中运行smtpd_senddata.py
。
$ python3 smtpd_custom.py
Receiving message from: ('127.0.0.1', 58541)
Message addressed from: author@example.com
Message addressed to : ['recipient@example.com']
Message length : 229
smtpd_senddata.py
的调试输出显示了与服务器的所有通信。
$ python3 smtpd_senddata.py
send: 'ehlo 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.
0.0.0.0.0.0.ip6.arpa..'
reply: b'250-1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0
.0.0.0.0.0.0.ip6.arpa..'
reply: b'250-SIZE 33554432..'
reply: b'250 HELP..'
reply: retcode (250); Msg: b'1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0
.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.SIZE 33554432.HELP'
send: 'mail FROM:<author@example.com> size=236..'
reply: b'250 OK..'
reply: retcode (250); Msg: b'OK'
send: 'rcpt TO:<recipient@example.com>..'
reply: b'250 OK..'
reply: retcode (250); Msg: b'OK'
send: 'data..'
reply: b'354 End data with <CR><LF>.<CR><LF>..'
reply: retcode (354); Msg: b'End data with <CR><LF>.<CR><LF>'
data: (354, b'End data with <CR><LF>.<CR><LF>')
send: b'Content-Type: text/plain; charset="us-ascii"..MIME-Ver
sion: 1.0..Content-Transfer-Encoding: 7bit..To: Recipient <r
ecipient@example.com>..From: Author <author@example.com>..Su
bject: Simple test message....This is the body of the messag
e......'
reply: b'250 OK..'
reply: retcode (250); Msg: b'OK'
data: (250, b'OK')
send: 'quit..'
reply: b'221 Bye..'
reply: retcode (221); Msg: b'Bye'
要停止服务器,请按Ctrl-C
。
调试服务器
上一个示例显示了process_message()
的参数,但是smtpd
还包括专门为更完整的调试而设计的服务器,称为DebuggingServer
。它将整个传入消息打印到控制台,然后停止处理(它不会将消息代理到真实的邮件服务器)。
smtpd_debug.py
import smtpd
import asyncore
server = smtpd.DebuggingServer(('127.0.0.1', 1025), None)
asyncore.loop()
使用以前的smtpd_senddata.py
客户端程序,DebuggingServer
的输出为:
---------- MESSAGE FOLLOWS ----------
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
To: Recipient <recipient@example.com>
From: Author <author@example.com>
Subject: Simple test message
X-Peer: 127.0.0.1
This is the body of the message.
------------ END MESSAGE ------------
## 代理服务器
PureProxy
类实现了一个简单的代理服务器。传入的消息将作为构造函数的参数提供给上游,转发给服务器。
警告
smtpd
的标准库文档说:“运行此程序有很大的机会使您进入开放中继,因此请小心。”
设置代理服务器的步骤与调试服务器相似。
smtpd_proxy.py
import smtpd
import asyncore
server = smtpd.PureProxy(('127.0.0.1', 1025), ('mail', 25))
asyncore.loop()
但是,它不会输出任何输出,因此要验证其是否正常运行,请查看邮件服务器日志。
Aug 20 19:16:34 homer sendmail[6785]: m9JNGXJb006785:
from=<author@example.com>, size=248, class=0, nrcpts=1,
msgid=<200810192316.m9JNGXJb006785@homer.example.com>,
proto=ESMTP, daemon=MTA, relay=[192.168.1.17]
另请参见
-smtpd的标准库文档
-[smtplib
](pymotw.com/3/smtplib/index.html#mo...“ smtplib:简单邮件传输协议客户端。”)–提供了客户端界面。
-电子邮件
-解析电子邮件。
-asyncore
-用于编写异步服务器的基本模块。
- RFC 2822 – Internet邮件格式*,定义电子邮件格式。
- RFC 5322 –取代RFC 2822。
本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。