go发送html邮件附件不显示的主因是net/mail不处理mime编码,需用mime/multipart手动构建multipart/mixed与multipart/alternative结构,注意boundary唯一、换行符完整、非ascii文件名用mime.bencoding.encode;smtp加密须用587端口+starttls;html样式须全部内联且禁用css类;大附件应预检大小或转云链接。

Go 发送 HTML 邮件时附件不显示或被当作纯文本
根本原因是 net/mail 不处理 MIME 编码逻辑,它只负责构造原始邮件头和正文结构;附件和 HTML 混合体必须手动组装 multipart/mixed 和 multipart/alternative 子段,稍有错位(比如 boundary 重复、换行符缺失、编码错误)就会导致客户端忽略附件或渲染为乱码。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 别直接拼接字符串,用
mime/multipart创建Writer,调用w.WriteField和w.CreatePart分层写入 - HTML 内容必须放在
multipart/alternative中,且 plain-text part 要在 HTML part 之前(否则 Outlook 可能只显示 text/plain) - 附件必须作为
multipart/mixed的顶层 part,不能嵌套进alternative里 - 所有非 ASCII 字符(包括中文文件名)必须用
mime.BEncoding.Encode处理,否则 Gmail 会丢附件名
smtp.SendMail 报错 “530 5.7.0 Must issue a STARTTLS command first”
这是 SMTP 服务器强制要求加密连接,但你用了明文 smtp.gmail.com:25 或未启用 TLS。Gmail、Outlook、腾讯企业邮箱等均已禁用非加密提交。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 改用
smtp.gmail.com:587+auth.SMTPAuth+ 显式tls.Config{InsecureSkipVerify: false} - 不要用
smtp.SendMail直连,改用gomail或手写net/smtp客户端并调用c.StartTLS - Gmail 必须开启「App Password」并用它代替账号密码,普通密码会直接被拒
- 测试时先 telnet 连一下端口确认通路:
telnet smtp.gmail.com 587,不通就不是代码问题
HTML 邮件在 iOS Mail 或 Outlook 中样式失效
不是 Go 的问题,是邮件客户端对 CSS 的支持极弱:iOS Mail 不支持 <style></style> 块,Outlook 用 Word 渲染引擎,几乎不认 Flex/Grid/float,还强制重置 margin/padding。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
- 所有样式必须内联(inline),用工具如
premailer-go或inliner库自动转换,别手写 - 避免
<div> 布局,改用 <code><table> + <code>cellpadding/cellspacing(老办法反而最稳) - 字体、颜色、链接必须用
style="..."属性写死,class和外部 CSS 全无效 - 图片务必加
alt属性和固定宽高,否则 Outlook 会撑开布局 - 发送前用
os.Stat检查附件大小,超过目标邮箱限制就提前报错,别等到WriteTo才卡住 - 用
io.Pipe+multipart.Writer流式写入,避免把整个附件读进内存 - 设置
smtp.Client的Timeout和KeepAlive,例如time.Minute * 5 - 生产环境优先考虑「附件转云链接」:上传到 COS/OSS 后发下载地址,比硬塞进邮件可靠得多
大附件(>10MB)发送失败或被服务商截断
SMTP 协议本身不限制大小,但实际中 Gmail 限制 25MB,腾讯企业邮箱 50MB,而且 Go 的 mime/multipart.Writer 默认不设缓冲,大文件容易 OOM 或超时。
实操建议:
立即学习“go语言免费学习笔记(深入)”;
边界值、编码顺序、客户端兼容性——这三块没一个靠文档能写对,必须拿真实邮箱收一遍再调。











