Рубрики
Без рубрики

smtpd – Примеры почтовых серверов

Автор оригинала: Doug Hellmann.

Цель:

Включает классы для реализации SMTP-серверов.

Модуль smtpd включает классы для создания серверов простого почтового транспортного протокола.

Базовый класс почтового сервера

Базовым классом для всех предоставленных примеров серверов является SMTPServer . Он обрабатывает общение с клиентом, получение входящих данных и обеспечивает удобный

Аргументы конструктора – это локальный адрес для прослушивания подключений и удаленный адрес, по которому должны доставляться прокси-сообщения. Метод process_message () предоставляется как перехватчик, который должен быть переопределен производным классом. Он вызывается, когда сообщение полностью получено, и с учетом следующих аргументов:

равноправный

Адрес клиента, кортеж, содержащий IP-адрес и входящий порт.

mailfrom

Информация “от” из конверта сообщения, передаваемая сервер клиентом, когда сообщение доставлено. Это не обязательно соответствовать

Из

заголовок во всех случаях.

rcpttos

Список получателей из конверта сообщения. Опять же, это не всегда

К

заголовок, особенно если получатель слепая копировальная копия.

данные

Полное тело сообщения 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 можно адаптировать для создания клиента на

smtpd_senddata.py

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_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\r\n'
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\r\n'
reply: b'250-SIZE 33554432\r\n'
reply: b'250 HELP\r\n'
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\nSIZE 33554432\nHELP'
send: 'mail FROM:
reply: b'250 OK\r\n'
reply: retcode (250); Msg: b'OK'
send: 'rcpt TO:\r\n'
reply: b'250 OK\r\n'
reply: retcode (250); Msg: b'OK'
send: 'data\r\n'
reply: b'354 End data with .\r\n'
reply: retcode (354); Msg: b'End data with .'
data: (354, b'End data with .')
send: b'Content-Type: text/plain;\r\nMIME-Ver
sion: 1.0\r\nContent-Transfer-Encoding: 7bit\r\nTo: Recipient \r\nFrom: Author \r\nSu
bject: Simple test message\r\n\r\nThis is the body of the messag
e.\r\n.\r\n'
reply: b'250 OK\r\n'
reply: retcode (250); Msg: b'OK'
data: (250, b'OK')
send: 'quit\r\n'
reply: b'221 Bye\r\n'
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;
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
To: Recipient 
From: Author 
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:
fromauthor@example.com>, size248, class0, nrcpts1,
msgid200810192316.m9JNGXJb006785@homer.example.com>,
protoESMTP, daemonMTA, relay[192.168.1.17]

Смотрите также