应优先使用gomail而非net/smtp:它自动处理mime构造、rfc 2047中文编码、auth降级及starttls协商,支持html正文与附件一键添加,且调用顺序严格——须先setbody("text/plain",...)再addalternative("text/html",...)。

别用 net/smtp 从零学 SMTP 协议再发邮件——你不是在学协议,是在搭生产告警通道。真要落地,直接上 gomail;想理解底层机制,才碰 go-smtp 或裸包。
gomail 发 HTML + 附件时 SetBody 和 AddAlternative 的调用顺序不能反
很多新手把 m.AddAlternative("text/html", "...") 放在 m.SetBody("text/plain", "...") 前面,结果 Outlook 只显示空白,Gmail 显示纯文本但没 HTML 版本。
- 必须先调
m.SetBody("text/plain", "..."),再调m.AddAlternative("text/html", "...") - 主题含中文?不用手动 RFC 2047 编码,
gomail自动处理 - 附件路径如
/tmp/report.pdf必须存在,且 Go 进程有读权限;内存中文件(比如*bytes.Buffer)要用m.Attach("file.xlsx", gomail.SetCopyFunc())
Gmail / 163 / 腾讯企业邮的端口与 TLS 配置必须严格匹配
连不上不是密码错,是加密协商卡死。同一域名下,:465 和 :587 对应完全不同的握手流程。
- Gmail:只用
"smtp.gmail.com:587"+ 默认 TLS(STARTTLS),别碰 465;密码必须是 App Password(两步验证开启后生成) - 163:支持
"smtp.163.com:465"(SSL)或"smtp.163.com:587"(STARTTLS);若选 465,测试可设d.TLSConfig = &tls.Config{InsecureSkipVerify: true},但生产必须校验证书 - 腾讯企业邮:
"smtp.exmail.qq.com:465"更稳;若用 587,得确认服务器实际支持 STARTTLS,否则DialAndSend会卡在协商阶段无报错
net/smtp.SendMail 报 535 / 432 / “unencrypted connection” 别查密码
这些错误全在协议层:AUTH 机制不匹配、STARTTLS 升级失败、或服务端拒绝明文连接。Go 1.9+ 默认禁止未加密的 SMTP 连接。
-
535 5.7.8 Username and Password not accepted:不是密码错,是认证方式不被支持(比如服务器只认 LOGIN,而net/smtp默认只试 PLAIN) -
432 4.3.2 Authentication mechanism not supported:同上,需自己实现 AUTH 降级逻辑,gomail内部已做 - “unencrypted connection”:端口 587 没走 STARTTLS,或端口 465 没用
tls.Dial直连
go-smtp 适合想看懂 AUTH/EHLO/MAIL FROM 流程的人
它不是为快速发告警设计的,而是帮你看清 SMTP 交互每一步。比如你想调试为什么某企业邮箱拒绝你的 MAIL FROM,或验证 PIPELINING 是否启用,go-smtp 的 client 日志和可插拔 auth handler 就比 gomail 透明得多。
- 用
sasl.NewPlainClient或sasl.NewLoginClient显式指定机制,比裸包更可控 - 邮件体必须手写完整 RFC 822 格式(
To:、Subject:、空行、正文),少一个\r\n都可能被拒收 - 它支持 LMTP、UTF-8 header 等扩展,但你要自己构造 MIME,附件/HTML 兼容性得额外处理
真正卡住人的从来不是“怎么发”,而是“为什么收件方看不到”——SPF 记录缺失、From 域名没授权、HTML 中用了不兼容 CSS、附件 MIME type 错标成 application/octet-stream 而不是 application/pdf。这些细节,gomail 帮你绕过前半截,但后半截还得靠收件方邮箱的原始报错头来定位。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











