bigywater.tech
Flask · 77

Flask-Mail 邮件发送

Flask-Mail 发出去的邮件到底长什么样?密送在哪里?测试里怎么不真发?在请求里同步发会不会卡住?这篇自己起一个 SMTP 服务接收邮件,把这些逐个量出来。

515 ms
SMTP 服务响应慢 0.5 秒时,同步 mail.send 阻塞请求的时间
Bcc
只出现在 SMTP 信封里,邮件头里没有
10 → 1
10 封邮件的 SMTP 会话数:各自 send 与 mail.connect()

邮件的真实样子

实测 · 本机执行输出
  信封:MAIL FROM=noreply@lab.test RCPT TO=['u@x.test']
  From: noreply@lab.test
  To: u@x.test
  Subject: 订单 #42 已发货
  Content-Type: multipart/mixed; boundary="===============7694008138832197402=="
  MIME-Version: 1.0
  原始 Subject 头(未解码): =?utf-8?b?6K6i5Y2VICM0MiDlt7Llj5HotKc=?=
  MIME 结构: [('multipart/mixed', None), ('multipart/alternative', None), ('text/plain', 'utf-8'), ('text/html', 'utf-8')]

上一篇:Flask-Limiter;下一篇:Flask-SocketIO 长连接。

附件、抄送与密送

实测 · 本机执行输出
  信封 RCPT TO: ['hidden@x.test', 'c@x.test', 'a@x.test', 'b@x.test']
  头 To: a@x.test, b@x.test | Cc: c@x.test | Bcc 头是否存在: False | Reply-To: support@lab.test
  MIME 结构: [('multipart/mixed', None), ('text/plain', None), ('text/csv', 'r.csv')]

测试时不真发

实测 · 本机执行输出
  TESTING=True 发 1 封:outbox 里 1 封,SMTP 服务端新增 0 封;扩展里的 suppress = True(配置里并没有写入 MAIL_SUPPRESS_SEND 这个键:False)
  outbox[0].subject / recipients: t ['u@x.test']
  TESTING=True 但显式 MAIL_SUPPRESS_SEND=False:服务端新增 1 封

头注入检查

实测 · 本机执行输出
  主题带换行 → BadHeaderError: 
  收件人带换行 → BadHeaderError: 

同步发送与线程

实测 · 本机执行输出
  在应用上下文之外构造 Message(没有显式 sender)→ RuntimeError: Working outside of application context.
  同步 send:515 ms;线程里 send:启动线程 0.51 ms 就返回(邮件在后台继续,总共 520 ms)

生产里更常见的是任务队列(Celery 等),本篇没有验证。

SMTP 不可用

实测 · 本机执行输出
  ConnectionRefusedError: [Errno 61] Connection refused(耗时 5 ms)
  视图里不处理这个异常 → HTTP 500

复用连接

实测 · 本机执行输出
  每封各 mail.send:131 ms,服务端看到 10 个 SMTP 会话;一个 mail.connect():60 ms,1 个会话

分步演示

Flask-Mail
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Python 3.14.7 / Flask 3.1.3 / Werkzeug 3.1.9 / Jinja2 3.1.6 / SQLAlchemy 2.1.1 / gunicorn 26.2.0(都装在自己的虚拟环境里);大多数实验用 Flask 的 test_client(直接调用 WSGI 应用,不经过网络),需要真实 HTTP 时另起 gunicorn 或开发服务器(端口 9600 以上,本机 127.0.0.1);计时用 time.perf_counter,数字每次运行会有小幅抖动。Flask-Mail 0.10.0、aiosmtpd 1.4.6(本机 127.0.0.1 上的 SMTP 接收端)
    • 没有验证:TLS/SSL 与认证(MAIL_USE_TLS、MAIL_USERNAME)、真实邮件服务商的行为与退信、HTML 邮件在各邮件客户端的渲染、大附件、Celery 等异步方案、远程 SMTP 的连接耗时
    京ICP备2026067502号-1京公网安备11010502063487号