Python中用smtplib发送带附件的HTML邮件方法
时间:2026-08-13 | 作者:冻月看渠 | 阅读:0说白了,smtplib做的只是传输原始字节流,本身并不会替你处理MIME结构。要是靠手动去拼接邮件内容,boundary一旦处理失误,附件就很容易“消失”,HTML内容也可能被直接当成纯文本来解析。
更稳妥的做法,是通过email模块里的MIMEMultipart等类来构造符合RFC 2822规范的邮件体,把层级关系、编码方式、Content-Disposition头以及SMTP配置这些关键细节都设置到位。
为什么直接用 smtplib.sendmail() 会丢失附件或HTML渲染?
因为 smtplib 本身不处理邮件结构,它只负责把原始字节流发出去。
如果你手动拼接 HTML 内容和附件二进制数据,很容易破坏 MIME 边界(boundary),导致收件端无法识别附件或把 HTML 当纯文本显示。
真正该用的是 email 标准库里的 MIMEMultipart 和 MIMEText、MIMEBase 等类来构造符合 RFC 2822 的多部分邮件体。
- 必须用
MIMEMultipart("mixed")作为根容器,再嵌套MIMEMultipart("alternative")放 HTML/plain 文本 - 附件要用
MIMEApplication或MIMEBase包装,并调用set_payload()+encoders.encode_base64() Content-Disposition: attachment头不能漏,否则 Outlook 等客户端可能内联显示而非下载
怎么正确添加 HTML 正文和多个附件?
关键在于层级:外层 mixed → 中层 alternative(放 text/html + text/plain)→ 外层同级追加附件节点。
顺序错了,附件就变成正文的一部分。
示例片段(注意变量名和路径):
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication
import smtplib
msg = MIMEMultipart("mixed")
msg["Subject"] = "测试带附件的HTML邮件"
msg["From"] = "sender@example.com"
msg["To"] = "receiver@example.com"
构造HTML正文部分
html_part = MIMEMultipart("alternative")
html_body = MIMEText("你好
这是 HTML 邮件
", "html", "utf-8")
plain_body = MIMEText("这是纯文本备用内容", "plain", "utf-8")
html_part.attach(plain_body)
html_part.attach(html_body)
msg.attach(html_part)
添加附件(假设文件在当前目录)
for file_path in ["report.pdf", "data.xlsx"]:
with open(file_path, "rb") as f:
part = MIMEApplication(f.read(), _subtype="pdf" if file_path.endswith(".pdf") else "vnd.openxmlformats-officedocument.spreadsheetml.sheet")
part.add_header("Content-Disposition", "attachment", filename=file_path)
msg.attach(part)
发送
先建立 SMTP 连接:server = smtplib.SMTP("smtp.example.com", 587),接着调用 server.starttls() 启用 TLS 加密;随后用 server.login("sender@example.com", "app_password") 完成账号登录,之后通过 server.send_message(msg) 把邮件发出去,最后再执行 server.quit() 关闭连接。
常见报错和对应修复点
smtplib.SMTPDataError: (554, b'Transaction failed') —— 多半是附件没设 Content-Disposition 或文件路径不存在;
UnicodeEncodeError: 'ascii' codec can't encode characters —— HTML 字符串没指定 charset="utf-8",或 MIMEText 初始化时漏了第三个参数;
- 所有
MIMEText必须显式传入"utf-8"编码,不能依赖默认 - 附件文件名含中文?用
Header类编码:from email.header import Header; part.add_header("Content-Disposition", "attachment", filename=Header("中文.pdf", "utf-8").encode()) - Gmail 拒绝登录?改用应用专用密码(App Password),且确保账户开启两步验证
附件太大或 HTML 含图片资源怎么办?
smtplib 对单次发送的数据量没硬限制,但邮箱服务商有(Gmail 是 25MB)。
超限会直接断连,不会抛出明确异常,只会卡在 send_message() 或返回模糊错误码。
- 超过 10MB 的附件建议转用云存储链接 + 文本说明,而非硬塞进邮件
- HTML 里引用本地图片?不行 —— 收件方看不到。要转成内联 base64(用
MIMEImage),或托管到公网 URL - 避免在 HTML 中写
,这种路径仅发件人本地有效
边界、编码、头字段、服务商限制——这四点漏掉任何一环,附件就大概率消失或 HTML 变乱码。
免责声明:文中图文均来自网络,如有侵权请联系删除,心愿游戏发布此文仅为传递信息,不代表心愿游戏认同其观点或证实其描述。
相关文章
更多-
- 软件编程专业入门指南:核心技能、学习路径与就业前景解析
- 时间:2026-09-01
-
- 后端开发语言选型指南:Java、Python、Go等主流技术对比
- 时间:2026-09-01
-
- Python实战:从零搭建购物车系统,详解类与对象核心概念
- 时间:2026-08-27
-
- Python进阶:利用dataclasses简化代码的实战指南
- 时间:2026-08-27
-
- 使用uv构建并发布Python包到PyPI的完整教程
- 时间:2026-08-27
-
- Python NumPy索引与切片完整代码示例
- 时间:2026-08-27
-
- Python字符串与列表基础:索引、切片及操作详解
- 时间:2026-08-27
-
- 10个Python自动化脚本,轻松提升工作效率
- 时间:2026-08-27
精选合集
更多大家都在玩
大家都在看
更多-
- 糖尿病完全不能吃糖吗
- 时间:2026-09-15
-
- 蚂蚁庄园小课堂2026年9月16日最新题目答案
- 时间:2026-09-15
-
- 小鸡答题今天的答案是什么2026年9月16日
- 时间:2026-09-15
-
- 蚂蚁庄园每日答题答案2026年9月16日
- 时间:2026-09-15
-
- 以下哪种粮食是酿造绍兴黄酒的主要原料 蚂蚁庄园今日答案9月16日
- 时间:2026-09-15
-
- 劝学名句“及时当勉励,岁月不待人”出自哪位诗人 蚂蚁庄园今日答案9.16
- 时间:2026-09-15
-
- 蚂蚁庄园今天答题答案2026年9月16日
- 时间:2026-09-15
-
- 蚂蚁庄园答题今日答案2026年9月16日
- 时间:2026-09-15
