根本原因是现代邮箱(如qq、163、outlook)已禁用账户密码直连smtp,必须使用授权码或应用专用密码;qq邮箱需开启smtp服务并获取16位授权码,go代码中smtp.plainauth第三参数须填授权码而非登录密码。

Go 发送邮件时为什么总是 auth: 535 5.7.8 Authentication failed
根本原因不是密码错了,而是多数邮箱服务商(如 QQ、163、Outlook)已停用“账户密码”直接登录 SMTP,必须改用“授权码”或“应用专用密码”。QQ 邮箱的 SMTP 地址是 smtp.qq.com:587,但如果你填的是账号密码,gomail 或 net/smtp 会直接返回这个错误。
实操建议:
- QQ 邮箱:登录网页版 → 设置 → 账户 → “POP3/IMAP/SMTP/Exchange/CardDAV/CalDAV服务” → 开启 SMTP 服务 → 获取“POP3/SMTP服务”授权码(16位,非登录密码)
- 163 邮箱:同理开启 SMTP,并使用“客户端授权码”,不是邮箱登录密码
- Go 代码中,
auth := smtp.PlainAuth("", "your_email@163.com", "your_app_password", "smtp.163.com")—— 第三个参数必须是授权码,不是明文密码
用 net/smtp 发文本邮件 vs gomail 发带附件的邮件
net/smtp 是 Go 标准库,轻量、无依赖,适合发纯文本;但构造 MIME 多部分邮件(含附件、HTML 正文、图片内嵌)非常繁琐,容易出错。而 gomail(gopkg.in/gomail.v2)封装了 MIME 构建逻辑,接口直观。
常见场景对比:
- 只发一句话通知(如“订单已创建”)→ 直接用
net/smtp.SendMail,5 行搞定 - 要发 HTML 正文 + 一个 PDF 订单文件 → 必须用
gomail,否则手动拼Content-Type和 boundary 容易格式错乱导致收件端显示为空白或乱码 -
gomail默认启用 TLS,net/smtp需手动包装smtp.Auth和tls.Config,稍不注意会连不上(比如 QQ SMTP 要求 STARTTLS,不能直连 465)
gomail 中 m.SetHeader 和 m.SetAddressHeader 的区别
这是实际编码中最常混淆的两个方法。它们都设邮件头,但语义和格式完全不同:
-
m.SetHeader("From", "admin@example.com")→ 输出原始字符串From: admin@example.com,不带姓名,且会被某些邮箱(如 Gmail)标记为“未验证发件人” -
m.SetAddressHeader("From", "运维小张", "admin@example.com")→ 输出From: =?UTF-8?B?5Zu+5rOo5ZCN?= <admin></admin>,自动做 MIME 编码和邮箱格式包裹,兼容性更好 -
To/Cc同理:多个收件人必须用m.SetAddressHeader("To", "张三", "zhang@x.com")多次调用,不能传数组;也不能用SetHeader拼逗号分隔字符串,否则 Outlook 会解析失败
本地测试时如何避免被当成垃圾邮件
开发阶段用自己邮箱反复发测试邮件,很容易触发服务商反垃圾策略(尤其 QQ 邮箱 1 小时最多发 50 封)。真正影响送达率的不是内容文字,而是协议层细节:
- 必须设置
Date头:m.SetHeader("Date", time.Now().Format(time.RFC1123Z)),缺失会导致部分企业邮箱拒收 - 不要省略
Message-ID:可用fmt.Sprintf("", uuid.NewString(), "example.com")生成,否则 Gmail 可能折叠为“其他” - 发件域名(
From的 @ 后部分)若未配置 SPF/DKIM 记录,即使测试通过,上线后也会大量进垃圾箱 —— 这点常被忽略,但无法在本地绕过
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











