net/mail仅适合解析单部分rfc 5322纯文本邮件,不支持mime多部分、自动解码rfc 2047字段或content-transfer-encoding解码;复杂邮件应使用go-message库。

net/mail 适合解析“已接收”的原始邮件文本
它不是用来收邮件的,也不连 SMTP;而是当你已经拿到一封符合 RFC 5322 格式的纯文本邮件(比如从文件、POP3/IMAP 响应体、日志中提取出来的完整原始内容)时,用 mail.ReadMessage 解析头和正文的轻量工具。
- 适用场景:邮件归档系统读取 .eml 文件、SMTP 代理记录原始报文后做简单分析、内部通知系统解析回执邮件
- 不适用场景:实时监听邮箱、自动下载新邮件、处理带大量附件或嵌套 multipart 的营销邮件
- 关键限制:不解析 MIME 多部分结构 —— 遇到
Content-Type: multipart/alternative,msg.Body就是一堆带 boundary 的原始字节,你得自己拆或换库
解析发件人、主题等字段必须手动解码 RFC 2047
中文/日文主题或带昵称的发件人(如 =?UTF-8?B?5L2g5aW9?= <user></user>)不会被 msg.Header.Get("From") 自动转义,直接输出就是乱码或编码串。
- 正确做法:对
From、Subject、To等字段,先用mail.ParseAddressList或mail.ParseAddress提取地址结构,再对.Name字段调用mime.DecodeWord - 常见错误:直接
fmt.Println(msg.Header.Get("Subject"))→ 输出=?UTF-8?B?5L2g5aW9?=,以为解析失败 - 注意:
msg.Header.AddressList("From")内部已调用mime.DecodeWord,所以.Name是解码后的,但msg.Header.Get("Subject")不会
读正文前必须检查 Content-Transfer-Encoding 和 Content-Type
msg.Body 是个 io.Reader,但它的内容可能是 base64、quoted-printable,也可能是裸 UTF-8;还可能根本不是文本(比如是 application/pdf 的二进制流)。
- 必须读
msg.Header.Get("Content-Type")判断是否为text/plain或text/html - 必须读
msg.Header.Get("Content-Transfer-Encoding"),常见值有base64、quoted-printable、7bit;忽略它会导致正文乱码或截断 - 示例片段:
encoding := strings.ToLower(msg.Header.Get("Content-Transfer-Encoding")) if encoding == "base64" { body = base64.NewDecoder(base64.StdEncoding, body) } else if encoding == "quoted-printable" { body = quotedprintable.NewReader(body) } plain, _ := io.ReadAll(body)
遇到 multipart 邮件?别硬刚,换 github.com/emersion/go-message
标准库 net/mail 对 multipart 完全无感。它把整个多部分结构当作文本正文塞进 msg.Body,boundary 解析、part 类型识别、嵌套递归……全得你自己写,极易出错且不可靠。
立即学习“go语言免费学习笔记(深入)”;
- 真实邮件中 >95% 是 multipart(HTML+纯文本+附件混合),硬用
net/mail解析等于在雷区写正则 -
go-message提供message.Read+part.Header.ContentType()+part.Body,天然支持递归遍历、自动解码、附件提取 - 兼容性好:完全遵循 RFC 5322/2045/2046,比手撕 boundary 稳定十倍
真正要解析现代邮件,net/mail 只能当“入门验证器”或“单部分兜底方案”;一旦涉及 HTML 正文、图片内联、附件名含中文,它就该让位了。










