Python发送HTML邮件需用MIMEMultipart('alternative')封装纯文本和HTML双版本,否则Outlook、QQ邮箱等客户端会当作纯文本渲染;必须使用table布局、内联样式、XHTML doctype,且中文需URL编码,mailto:仅预填内容不真正发信。

用 mailto: 链接模拟“发信”,但收不到回信
浏览器里点一下就调起本地邮件客户端(Outlook、Mail、Foxmail),这不算真正“发信”,只是预填内容——mailto: 不走服务器,也不校验邮箱是否存在,更不会返回“发送成功”或“失败”。你填的 to、subject、body 全部拼成 URL,例如:mailto:admin@example.com?subject=%E6%B5%8B%E8%AF%95&body=%E4%BD%A0%E5%A5%BD。中文必须 encodeURIComponent() 编码,否则链接直接失效。
常见错误现象:点击无反应 → 检查浏览器是否禁用了外部协议;收件人显示乱码 → body 里没编码空格和中文;Gmail 网页版不响应 mailto: → 它默认忽略该协议,得用 Chrome 或 Edge 才行。
用 Python + smtplib 模拟“发信”,但收件人看不到 HTML 格式
很多人写完 MIMEText(html_body, 'html', 'utf-8') 就以为完事了,结果邮件客户端(尤其是 Outlook 和 QQ 邮箱)把它当纯文本渲染。根本原因是没包进 MIMEMultipart('alternative'),也没把 plain 文本和 HTML 版本都 attach 进去。
正确做法是:
立即学习“前端免费学习笔记(深入)”;
- 用
MIMEMultipart('alternative')创建根消息对象 - 分别构建
MIMEText(plain_body, 'plain', 'utf-8')和MIMEText(html_body, 'html', 'utf-8') - 两个都
.attach()到根对象上 - 别漏掉
msg['To']、msg['From']、msg['Subject']这些头字段,否则某些客户端会拒收
示例关键片段:
msg = MIMEMultipart('alternative')<br>msg['From'] = 'you@domain.com'<br>msg['To'] = 'user@example.com'<br>msg['Subject'] = '测试邮件'<br><br>part1 = MIMEText('纯文本内容', 'plain', 'utf-8')<br>part2 = MIMEText('<h1>HTML内容</h1>', 'html', 'utf-8')<br>msg.attach(part1)<br>msg.attach(part2)写 HTML 邮件模板时,<table> 不是复古,是刚需
别信“用 Flexbox 做响应式邮件”这种教程。Gmail 会剥离 <style> 标签,Outlook for Windows 直接忽略 CSS Grid,Apple Mail 对 @media 查询支持极差。唯一能跨客户端对齐、撑开、居中、分栏的,只有 <table>。
必须遵守的硬规则:
- 最外层套一个
<table width="100%">,里面再嵌一个<table width="600">作内容区 - 所有样式写在
属性里,比如<p style="font-size:14px; margin:0"> - 图片加
border="0"和style="display:block",否则 Outlook 默认加蓝边、Gmail 插入多余空白 - 别用
<div>、<section>、<header>—— 大部分客户端直接丢弃整块内容
Doctype 必须用 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">,哪怕你只写个 <html> 标签,Gmail 也会偷偷替换成这个。
所谓“模拟收信箱”,本质是绕不开 SMTP 和 IMAP 的假象
前端页面里放个 <iframe src="https://mail.google.com/mail/u/0/#inbox">?不行,跨域被拦死。用 fetch 调 Gmail API?需要 OAuth2 授权、用户手动同意、后端代理,早超出“简单模拟”范畴。所谓“模拟收信箱”,实际只有两条路:
- 用 Python 的
imaplib连真实邮箱(需开启 IMAP、提供 App Password),拉取最新几封,解析email.message_from_bytes()得到主题、发件人、HTML 正文 —— 但这不是“模拟”,是真连服务器 - 纯前端 mock:造几条 JSON 数据,渲染成列表,点开后展示预设 HTML 内容 —— 完全不触网,也收不到真实邮件
最容易被忽略的一点:所有“收信箱”演示项目,只要没配真实 IMAP 账号或没跑通 OAuth 流程,就只是静态数据轮播。它不验证邮箱密码,不处理邮件加密,也不应对垃圾邮件过滤规则 —— 这些才是真实收信箱每天在扛的东西。



















