net/smtp仅实现smtp协议传输,需手动构造符合rfc 5322/2046的邮件字节流:头字段必填、换行用\r\n、空行分隔头与正文、中文subject需base64编码、content-type须显式声明charset=utf-8(无引号)、发件人必须与认证账号一致;端口587配starttls,465需tls.dial;html邮件必须用multipart结构,手动构造易出错;生产环境推荐gomail封装mime;各邮箱服务商对授权码、端口、加密方式要求严格,需按实际配置调试。

net/smtp 能发邮件,但不是“调个函数就发出去”,它只管协议传输,不帮你拼邮件头、不处理 HTML、不封装附件——想发成功,得自己按 RFC 5322 和 RFC 2046 把字节流写对。
怎么用 smtp.SendMail 发纯文本邮件
这是最简路径,适合通知类、日志告警等无格式需求。关键不是写代码,而是构造符合规范的原始邮件字节:From、To、Subject 必须有,\r\n 换行不能错,头部和正文之间必须空一行。
-
Subject中文要 Base64 编码(如Subject: =?UTF-8?B?5byg5LiJ?=),否则 Outlook 可能显示乱码 -
Content-Type: text/plain; charset=utf-8头必须显式写,不能省;charset值里不要加引号("utf-8"是错的) - 发件人地址(
from参数)必须和认证账号完全一致,Gmail/163/QQ 都校验这个,填错直接 530 5.7.0 Sender address rejected - 端口选
587就配smtp.PlainAuth+StartTLS;选465就得用tls.Dial直连,smtp.SendMail不支持自动 SSL 握手
示例片段:
msg := []byte("To: user@example.com\r\n" +
"From: sender@163.com\r\n" +
"Subject: =?UTF-8?B?5byg5LiJ?= \r\n" +
"MIME-Version: 1.0\r\n" +
"Content-Type: text/plain; charset=utf-8\r\n" +
"\r\n" +
"这是一封测试邮件。")
为什么发 HTML 邮件总显示源码
因为 net/smtp 完全不管 MIME 结构——你直接把 <h1>Hello</h1> 当正文塞进去,它就真当纯文本发了,收件箱自然渲染不出标题。HTML 邮件本质是 multipart/mixed 或 multipart/alternative 消息体,含 boundary、headers、text/html part 等,标准库不封装这些。
- 手动构造太容易出错:boundary 写错、part 缺
Content-Type、\r\n混成\n,都会导致 Gmail 显示为源码或拒收 - 内联样式必须用
style="..."行内写,<style></style>标签多数邮箱会过滤;图片必须用绝对 URL,cid:引用需额外构造 related part,net/smtp不支持 - 别信“改个
Content-Type: text/html就行”的说法——那只是告诉客户端“我打算发 HTML”,但没提供合法 MIME 包裹,SMTP 服务端可能静默降级为 text/plain
该不该自己封装 MIME,还是用 gomail
除非你在写邮件协议学习项目,否则别手撸 MIME。生产环境用 github.com/go-gomail/gomail(v3)是更稳的选择:它底层仍走 net/smtp,但把 multipart 构造、header 编码、附件嵌入、HTML/text 双版本 fallback 全包了。
-
gomail的m.SetBody("text/html", htmlStr)会自动生成 boundary 和 proper headers;加文本版只需再调一次m.SetBody("text/plain", plainStr),它就自动组装multipart/alternative - 附件用
m.Attach("/path/to/file.pdf"),比自己读文件+base64+写 header+插 boundary 省心太多 - 注意 v3 默认不复用连接,高频发送需手动管理
gomail.Dialer实例并调用d.Dial()/d.Close(),否则可能触发服务商连接数限制 - 它不解决 SMTP 认证问题——
gomail的auth还是得传smtp.PlainAuth,密码仍需应用专用密码,这点和裸用net/smtp一样
QQ 邮箱 / Gmail / 163 邮箱的实际配置差异
服务商对 SMTP 的要求差异比文档写的更细,硬套通用配置大概率失败。
- Gmail:必须开两步验证,再生成「应用专用密码」;
smtp.gmail.com:587+smtp.PlainAuth是唯一推荐组合;用:465会报 454 4.7.0 TLS not available;from字段必须是完整邮箱,且和 auth 用户名一致 - QQ 邮箱:设置页开启「POP3/IMAP/SMTP 服务」后,获取的是独立「授权码」,不是登录密码;
smtp.qq.com:587和:465都可用,但:465需用tls.Dial手动建连接,smtp.SendMail不兼容 - 163 邮箱:只认
smtp.163.com:465(SSL),且必须用授权码;from如果填user@163.com,auth 用户名也得是user@163.com,少个域名就 535 错误 - 所有服务商都拒绝明文密码直传——别在代码里写死密码,务必用
os.Getenv("SMTP_PASSWORD")或配置中心注入
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











