13.2 smtpd:示例邮件服务器
smtpd模块包括一些用于构建简单邮件传输协议(SMTP)服务器的类。这是smtplib所使用协议的服务器端。
13.2.1 邮件服务器基类
已经提供的所有示例服务器的基类都是SMTPServer。它会处理与客户的通信以及接收到来的数据,还提供了一个方便的hook,可以覆盖这个hook,一旦得到完整的消息就可以进行处理。
构造函数参数包括监听连接的本地地址和要发送代理消息的远程地址。process_message()方法作为一个hook提供,要由派生类覆盖。接收到完整的消息时会调用这个方法,并指定以下参数:
peer:客户的地址,这是一个包含IP和入站端口的元组。
mailfrom:消息信封中的“from”信息,传送消息时由客户提供给服务器。这个消息不一定总与From首部匹配。
rcpttos:消息信封中的接收者列表。同样,这个列表不一定总与To首部匹配,特别是暗送给接收者时。
data:完整的RFC 5322消息体。
process_message()的默认实现会产生NotImplementedError。下面的例子定义了一个子类,它覆盖了这个方法,会打印接收到的消息的有关信息。
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一节中的某个例子来创建一个客户,向在端口1025上本地运行的测试服务器发送数据。
import smtplib
import email.utils
from email.mime.text import MIMEText
# Create the message.
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) # Show communication with the server.
try:
server.sendmail('author@example.com',
['recipient@example.com'],
msg.as_string())
finally:
server.quit()
要测试这些程序,可以在一个终点窗口运行smtpd_cunstom.py,在另一个终点窗口运行smtpd_senddata.py。
smtpd_senddata.py的调试输出显示了与服务器的所有通信。