smtp.SendMail 的 msg 参数必须是符合 RFC 822 标准的完整邮件内容,含正确格式的头部(From、To、Subject 等)、CRLF 换行、空行分隔及编码规范的正文,否则将导致发件人缺失、主题乱码、被拒收或归入垃圾箱。

smtp.SendMail 的 body 参数必须包含完整邮件头
很多人以为 smtp.SendMail 的第5个参数(msg)只是正文,结果发出去的邮件没发件人、没主题,甚至被 Gmail 直接扔进垃圾箱。根本原因是:这个参数必须是符合 RFC 822 的完整邮件内容,含头部 + 空行 + 正文。
常见错误现象:From 字段不显示、收件端看到“无主题”、Outlook 解析失败、Gmail 标记为“未验证发件人”
- 头部字段必须用
\r\n换行(Windows 风格),不能只用\n - 头部与正文之间必须是
\r\n\r\n(两个连续 CRLF),少一个都会解析失败 -
From、To、Subject是必需字段;Content-Type: text/plain; charset=UTF-8强烈建议显式声明,避免乱码 - 中文主题必须 MIME 编码,例如
Subject: =?UTF-8?B?5byg5LiJ55WM?=,否则 Outlook/Gmail 会显示问号
授权码不是登录密码,QQ/163/Gmail 都强制要求
运行时遇到 535 5.7.8 Authentication failed,99% 不是密码输错了,而是你填了邮箱登录密码——现代服务商已全面禁用该方式直连 SMTP。
使用场景:所有主流国内/国际邮箱(QQ、163、Gmail、Outlook)均适用
立即学习“go语言免费学习笔记(深入)”;
- QQ 邮箱:网页版 → 设置 → 账户 → “POP3/IMAP/SMTP/Exchange 服务” → 开启并获取 16 位授权码
- 163 邮箱:同路径开启 SMTP,使用“客户端授权码”,不是登录密码
- Gmail:需开启“两步验证”后生成“应用专用密码”,且账户要启用“允许不够安全的应用”(或改用 OAuth2)
- 代码中
smtp.PlainAuth("", "user@xx.com", "your_app_password", "smtp.xx.com")第三个参数必须是授权码
端口和 TLS 配置错一个就连接失败
QQ 和 Gmail 常见组合是 smtp.qq.com:587 + STARTTLS,但有人硬套 :465 + SSL,结果 dial tcp: lookup smtp.qq.com: no such host 或直接 timeout。
性能与兼容性影响:465 端口要求 TLS 握手在连接建立时立即开始(SSL/TLS);587 端口则走明文连接后再发 STARTTLS 命令升级(机会加密),两者不可混用
- 587 端口:用
smtp.PlainAuth即可,Go 的net/smtp内部会自动处理 STARTTLS - 465 端口:必须用
tls.Dial手动建连接,再传给smtp.Client,smtp.SendMail不支持 - 腾讯云 SES、SendGrid 等云服务多用 465 或 587,务必查清文档,别凭经验填
- 若用
gomail库,它默认启用 TLS,但需显式调用m.SetAddressHeader("From", ...)才能正确编码中文姓名
发件人字段写法决定邮箱客户端是否信任你
m.SetHeader("From", "admin@example.com") 和 m.SetAddressHeader("From", "运维小张", "admin@example.com") 看似只差一个函数名,但后者生成的是标准 MIME 格式:From: =?UTF-8?B?5Zu+5rOo5ZCN?= <admin@example.com>,前者只是裸字符串,Gmail 会标红警告“此发件人未经验证”。
容易踩的坑:多个收件人不能拼成逗号分隔字符串传给 SetHeader("To", ...),必须对每个收件人单独调用 SetAddressHeader("To", name, addr)
-
SetHeader适合设纯技术字段,如Content-Transfer-Encoding -
SetAddressHeader专用于From、To、Cc、Reply-To,自动做 base64 编码 + 角括号包裹 - 如果用
net/smtp而非gomail,就得自己拼To: =?UTF-8?B?zrHOss6yzrM=?= <user@x.com>,极易出错 - 别忽略
Return-Path,生产环境建议显式设置,便于退信归集


















