- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我想用 aiosmtpd 在 python 中编写我自己的小型邮件服务器应用程序
a) 用于教育目的以更好地理解邮件服务器
b) 实现自己的特点
所以我的问题是,Mail-Transfer-Agent 缺少什么(除了 aiosmtpd),它可以向/从其他完整的 MTA(gmail.com、yahoo.com)发送和接收电子邮件...)?
我猜:
1.) 当然是域 和静态 ip
2.) 此域的有效证书
...应该可以使用 Lets Encrypt
3.) 加密
...应该可以使用 SSL/Context/Starttls...使用 aiosmtpd 本身
4.) 正在解析 外发电子邮件的 MX DNS 条目!?
...应该可以使用 python 库 dnspython
5.) Error 处理 SMTP 通信错误、来自其他 MTA 的错误回复、弹跳!?
6.) Queue 用于处理入站和待处理的出站电子邮件!?
是否缺少任何其他“基本”功能?
我当然知道,邮件服务器还有很多“高级”功能,例如垃圾邮件检查、恶意软件检查、证书验证、黑名单、规则、邮箱等等...
感谢所有提示!
编辑:
让我澄清一下我的想法:
我想为一个俱乐部写一个邮件服务器。它的主要用途将是一个邮件列表服务器。俱乐部的不同群体会有不同的名单。假设我的域名是 myclub.org 那么就会有例如 youth@myclub.org、trainer@myclub.org 等等。
只有成员(member) 才能使用此邮件服务器,并且只有成员(member)才能收到来自此邮件服务器的电子邮件。不允许其他任何人向该邮件服务器发送电子邮件,也不得从其接收电子邮件。成员的电子邮件地址及其组存储在数据库中。
将来我想集成一些其他有用的功能,例如:
我不需要的:
开放中继问题:
丢失电子邮件问题:
我想我需要一个“轻量级”重试机制。但是,如果外发电子邮件在重试几次后无法送达,它将被丢弃,并且只会通知管理员,而不是发件人。成员不应被电子邮件发送问题所困扰。是否有任何Python 库 可以生成符合RFC3464 标准 错误回复电子邮件?
重启问题:
我不确定我是否真的需要永久存储尚未发送的电子邮件?在我的用例中,所有外发电子邮件通常应该在几秒钟内送达(如果没有发生送达问题)。在(计划的)重新启动之前,我可以检查一个空的发送队列。
最佳答案
aiosmtpd 是为电子邮件编写自定义路由和 header 重写规则的出色工具。但是,aiosmtpd 不是 MTA,因为它不进行消息排队或 DSN 生成。 MTA 的一个流行选择是 postfix,并且由于可以将 postfix 配置为将某个域的所有电子邮件中继到另一个本地 SMTP 服务器(例如 aiosmtpd),因此自然的选择是使用 postfix 作为面向 Internet 的前端,并将 aiosmtpd 作为业务-逻辑后端。
使用 postfix 作为中间人而不是让 aiosmtpd 面向公共(public)互联网的优势:
以下是您可以如何配置 postfix 以与由例如支持的本地 SMTP 服务器一起工作aiosmtpd.
我们将在端口 25 上运行 postfix,在端口 20381 上运行 aiosmtpd。
要指定 postfix 应将 example.com
的电子邮件中继到在端口 20381 上运行的 SMTP 服务器,请将以下内容添加到 /etc/postfix/main.cf
:
transport_maps = hash:/etc/postfix/smtp_transport
relay_domains = example.com
并创建 /etc/postfix/smtp_transport
,内容如下:
# Table of special transport method for domains in
# virtual_mailbox_domains. See postmap(5), virtual(5) and
# transport(5).
#
# Remember to run
# postmap /etc/postfix/smtp_transport
# and update relay_domains in main.cf after changing this file!
example.com smtp:127.0.0.1:20381
在创建该文件后(以及每次修改它时)运行 postmap/etc/postfix/smtp_transport
。
在 aiosmtpd 方面,有几件事需要考虑。
最重要的是您如何处理退回邮件。简而言之,您应该将信封发件人设置为您控制的专门用于接收退回邮件的电子邮件地址,例如bounce@example.com
。当电子邮件到达此地址时,它应该存储在某个地方,以便您可以处理退回邮件,例如通过从您的数据库中删除成员电子邮件地址。
另一个需要考虑的重要事项是您如何告知成员(member)的电子邮件提供商您正在进行邮件列表转发。将电子邮件转发到 GROUP@example.com
时,您可能需要添加以下 header :
Sender: bounce@example.com
List-Name: GROUP
List-Id: GROUP.example.com
List-Unsubscribe: <mailto:postmaster@example.com?subject=unsubscribe%20GROUP>
List-Help: <mailto:postmaster@example.com?subject=list-help>
List-Subscribe: <mailto:postmaster@example.com?subject=subscribe%20GROUP>
Precedence: bulk
X-Auto-Response-Suppress: OOF
在这里,我使用 postmaster@example.com
作为列表取消订阅请求的收件人。这应该是转发给电子邮件管理员(即您)的地址。
下面是一个框架(未经测试),它完成了上面的工作。它将退回的电子邮件存储在名为 bounces
的目录中,并根据组列表(在 >群组
).
import os
import email
import email.utils
import mailbox
import smtplib
import aiosmtpd.controller
LISTEN_HOST = '127.0.0.1'
LISTEN_PORT = 20381
DOMAIN = 'example.com'
BOUNCE_ADDRESS = 'bounce'
POSTMASTER = 'postmaster'
BOUNCE_DIRECTORY = os.path.join(
os.path.dirname(__file__), 'bounces')
def get_extra_headers(list_name, is_group=True, skip=()):
list_id = '%s.%s' % (list_name, DOMAIN)
bounce = '%s@%s' % (BOUNCE_ADDRESS, DOMAIN)
postmaster = '%s@%s' % (POSTMASTER, DOMAIN)
unsub = '<mailto:%s?subject=unsubscribe%%20%s>' % (postmaster, list_name)
help = '<mailto:%s?subject=list-help>' % (postmaster,)
sub = '<mailto:%s?subject=subscribe%%20%s>' % (postmaster, list_name)
headers = [
('Sender', bounce),
('List-Name', list_name),
('List-Id', list_id),
('List-Unsubscribe', unsub),
('List-Help', help),
('List-Subscribe', sub),
]
if is_group:
headers.extend([
('Precedence', 'bulk'),
('X-Auto-Response-Suppress', 'OOF'),
])
headers = [(k, v) for k, v in headers if k.lower() not in skip]
return headers
def store_bounce_message(message):
mbox = mailbox.Maildir(BOUNCE_DIRECTORY)
mbox.add(message)
MEMBERS = ['foo@example.net', 'bar@example.org',
'clubadmin@example.org']
GROUPS = {
'group1': ['foo@example.net', 'bar@example.org'],
POSTMASTER: ['clubadmin@example.org'],
}
class ClubHandler:
def validate_sender(self, message):
from_ = message.get('From')
if not from_:
return False
realname, address = email.utils.parseaddr(from_)
if address not in MEMBERS:
return False
return True
def translate_recipient(self, local_part):
try:
return GROUPS[local_part]
except KeyError:
return None
async def handle_RCPT(self, server, session, envelope, address, rcpt_options):
local, domain = address.split('@')
if domain.lower() != DOMAIN:
return '550 wrong domain'
if local.lower() == BOUNCE:
envelope.is_bounce = True
return '250 OK'
translated = self.translate_recipient(local.lower())
if translated is None:
return '550 no such user'
envelope.rcpt_tos.extend(translated)
return '250 OK'
async def handle_DATA(self, server, session, envelope):
if getattr(envelope, 'is_bounce', False):
if len(envelope.rcpt_tos) > 0:
return '500 Cannot send bounce message to multiple recipients'
store_bounce_message(envelope.original_content)
return '250 OK'
message = email.message_from_bytes(envelope.original_content)
if not self.validate_sender(message):
return '500 I do not know you'
for header_key, header_value in get_extra_headers('club'):
message[header_key] = header_value
bounce = '%s@%s' % (BOUNCE_ADDRESS, DOMAIN)
with smtplib.SMTP('localhost', 25) as smtp:
smtp.sendmail(bounce, envelope.rcpt_tos, message.as_bytes())
return '250 OK'
if __name__ == '__main__':
controller = aiosmtpd.controller.Controller(ClubHandler, hostname=LISTEN_HOST, port=LISTEN_PORT)
controller.start()
print("Controller started")
try:
while True:
input()
except (EOFError, KeyboardInterrupt):
controller.stop()
关于Python aiosmtpd - 邮件传输代理 (MTA) 缺少什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45734960/
我正在尝试创建一个 aiosmtpd 服务器来处理收到的电子邮件。它在没有身份验证的情况下工作得很好,但我就是不知道如何设置身份验证。我已经浏览了文档并搜索了这方面的示例。 我目前如何使用它的示例:
关闭。这个问题需要多问focused 。目前不接受答案。 想要改进此问题吗?更新问题,使其仅关注一个问题 editing this post . 已关闭 6 年前。 Improve this ques
我想用 aiosmtpd 在 python 中编写我自己的小型邮件服务器应用程序 a) 用于教育目的以更好地理解邮件服务器 b) 实现自己的特点 所以我的问题是,Mail-Transfer-Agent
我正在尝试使用 python 和 aiosmtpd 库在我的计算机上运行我自己的 stmp 服务器。 我运行示例,一切看起来都很好,但我从未收到另一端的电子邮件。 不知道有没有日志可以看 我正在使用
我几乎直接从 aiosmtpd 文档中获取了以下服务器: import asyncio import ssl from aiosmtpd.controller import Controller cl
我是一名优秀的程序员,十分优秀!