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。

本文章首发在 LearnKu.com 网站上。

本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。

原文地址:https://learnku.com/docs/pymotw/smtpd-sa...

译文地址:https://learnku.com/docs/pymotw/smtpd-sa...

上一篇 下一篇
贡献者:2
讨论数量: 0
发起讨论 只看当前版本


暂无话题~