import os
import asyncio
import logging
import base64
from email import message_from_bytes
from email.message import Message
from datetime import datetime import aiosmtpd
from aiosmtpd.controller import Controller
from aiosmtpd.smtp import SMTP as Server, syntax
from jinja2 import Template mail_path = "mails"
hostname = "0.0.0.0"
port = 8025 html = """\
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>email</title>
</head>
<body>
<div><span>发件人: </span><span>{{ from_addr|e }}</span></div>
<div><span>收件人: </span><span>{{ to_addr|e }}</span></div>
<div><span>主题: </span><span>{{ subject }}</span></div>
<div>
{{ payload }}
</div>
</body>
</html>
""" class ExampleHandler:
async def handle_RCPT(self, server, session, envelope, address, rcpt_options):
envelope.rcpt_tos.append(address)
return "250 OK" async def handle_DATA(self, server, session, envelope: aiosmtpd.smtp.Envelope):
message: Message = message_from_bytes(envelope.content)
message_info = await self.parse_message(message)
template = Template(html)
if not os.path.exists(mail_path):
os.makedirs(mail_path)
with open(os.path.join(mail_path, f"mail_{datetime.now().strftime('%Y-%m-%d-%H_%M_%S_%f')[:-3]}.html"), "w") as f:
f.write(template.render(message_info))
return "250 Message accepted for delivery" def get(self, message, item):
value = message.get(item)
try:
value = self.to_true_str(value)
except Exception:
pass
return value async def parse_message(self, message: Message):
self.charset = message.get_content_charset() or "utf-8"
payload = message.get_payload()
subject = self.get(message, "Subject")
from_addr = self.get(message, "From")
to_addr = self.get(message, "To")
try:
if isinstance(payload, (list, tuple)):
payload = self.parse_payload(payload)
except Exception:
pass
return {"subject": subject, "payload": payload, "from_addr": from_addr, "to_addr": to_addr} def parse_payload(self, payload):
# todo 暂时不处理附件的问题,目前仅处理 text/html 与 text/plain 共存的情况
data = None
for item in payload:
if isinstance(item, Message):
data = item.get_payload()
if item.get_content_type == "text/html":
break try:
# 测试发现 html 有概率是转 base64
data = self.to_true_str(data)
except Exception:
pass return data def to_true_str(self, raw: str, charset=None):
if raw.startswith("=?"):
tmp_list = raw.split("?")
if len(tmp_list) > 2:
raw = tmp_list[-2]
charset = tmp_list[1]
else:
charset = self.charset
return base64.b64decode(raw).decode(charset) async def handle_EHLO(self, *args, **kwargs):
return """\
250-mail
250-PIPELINING
250-AUTH LOGIN PLAIN
250-AUTH=LOGIN PLAIN
250-coremail
250-STARTTLS
250-SMTPUTF8
250 8BITMIME""" class MyServer(Server): @syntax("AUTH PLAIN")
@asyncio.coroutine
def smtp_AUTH(self, PLAIN, *args, **kwargs):
yield from self.push("235 auth successfully") @syntax("EHLO hostname")
async def smtp_EHLO(self, hostname):
status = await self._call_handler_hook("EHLO", hostname)
self.session.host_name = hostname
await self.push(status) class MyController(Controller):
def factory(self):
return MyServer(self.handler) async def amain(loop):
controller = MyController(ExampleHandler(), hostname=hostname, port=port)
controller.start() if __name__ == "__main__":
logging.basicConfig(level=logging.ERROR)
loop = asyncio.get_event_loop()
loop.create_task(amain(loop=loop))
try:
loop.run_forever()
except KeyboardInterrupt:
pass

最新文章

  1. Quartz定时任务
  2. Ubuntu 16.10下的eclipse
  3. os.environ()
  4. 论文笔记之:Pedestrian Detection aided by Deep Learning Semantic Tasks
  5. iOSTab bar
  6. AppUse学习笔记
  7. JAVA中创建线程的三种方法及比较
  8. 配置ADB到Windows环境变量
  9. 转 jquery获取两个标签之间文本
  10. IP简介(一)
  11. [译]使用NuGet管理共享代码
  12. 【leetcode】441. Arranging Coins
  13. k8s定义Deployment,和service
  14. 初始化应用程序数据ng-init指令
  15. jQuery.lazyload详解(转)
  16. POJ1128 Frame Stacking(拓扑排序+dfs)题解
  17. fatal error LNK1112: 模块计算机类型“X86”与目标计算机类型“x64”冲突——我的解决方案
  18. 安卓API首页
  19. JZOJ.5288【NOIP2017模拟8.17】球场大佬
  20. 浅析Spring AOP

热门文章

  1. GDI 直线和折线(6)
  2. 训练1-V
  3. 洛谷 U3346 A1-偶回文数
  4. 【基础训练】HDOJ2032杨辉三角
  5. Codeforces Round #168 (Div. 2)---A. Lights Out
  6. Solr 搜索的过程和所须要的參数
  7. iOS开发-文件管理之多的是你不知道的事(一)
  8. hibernate 管理 Session(单独使用session,非spring)
  9. js+ canvas 实现人物走动
  10. hadoop(七) - hadoop集群环境搭建