Go用net/smtp连不上SMTP服务器主因是认证方式与端口不匹配:Gmail等需应用专用密码,587端口用STARTTLS,465需tls.Dial;企业邮箱可能拦截非白名单IP;发信失败需据错误码(如535、550)及telnet测试定位问题。

Go 用 net/smtp 发邮件为什么连不上 SMTP 服务器?
绝大多数连接失败不是代码写错,而是没处理好认证方式和端口匹配。Gmail、Outlook、阿里云邮箱等都默认禁用“密码直连”,必须用应用专用密码或开启 SMTP 服务权限。
-
smtp.gmail.com要求开启“两步验证”后生成应用专用密码,不能用账户登录密码 - 端口选错很常见:
587(STARTTLS)和465(SMTPS)不互通,net/smtp原生只支持587;用465必须套一层tls.Dial - 部分企业邮箱(如腾讯企业邮)会拦截非白名单 IP 的 SMTP 连接,本地开发时容易被静默拒绝
如何构造一封带附件和 HTML 正文的邮件?
Go 标准库没有开箱即用的 multipart 邮件封装,得手动拼 mime/multipart,但别自己从头写边界和头字段——用 gomail 这类轻量第三方包更稳。
-
gomail不依赖 cgo,纯 Go 实现,go get gopkg.in/gomail.v2即可引入 - HTML 正文直接设
m.SetBody("text/html", "<h1>Hi</h1>"),纯文本自动 fallback - 附件用
m.Attach("/path/to/file.pdf"),路径必须存在且进程有读权限;内存中生成的文件建议用m.Embed()+bytes.NewReader() - 别在
SetBody里传含中文的字符串而不设 charset,否则收件端可能显示乱码:显式写"text/html; charset=utf-8"
发信失败时怎么快速定位是认证问题还是网络问题?
错误信息里藏关键线索:dial tcp: lookup smtp.xxx.com: no such host 是 DNS 或域名写错;535 5.7.8 Username and Password not accepted 才是认证失败。
- 先用
telnet smtp.gmail.com 587或nc -v smtp.gmail.com 587测试基础连通性 - 连通后手动发
EHLO example.com看返回是否含AUTH LOGIN,确认服务器支持该认证方式 - Go 里捕获
err后,打印完整错误而非只fmt.Println(err)——net/smtp错误常带状态码,比如535、452都代表不同含义 - 如果用
gomail,启用调试模式:gomail.SetDebugWriter(os.Stdout),能看到原始 SMTP 交互帧
为什么定时发信任务总在凌晨挂掉?
不是代码逻辑问题,大概率是 SMTP 提供商对单 IP 的发信频率做了限制,尤其是免费邮箱服务。
立即学习“go语言免费学习笔记(深入)”;
- Gmail 免费账号每天上限约 500 封,超出后后续请求直接返回
550 5.4.5 Daily sending quota exceeded - 阿里云邮件推送虽不限量,但要求域名完成 DMARC/DKIM/SPF 配置,否则大量进垃圾箱甚至被拒收
- 本地测试用
mailhog搭个假 SMTP 服务(docker run -d -p 1025:1025 -p 8025:8025 mailhog/mailhog),避免反复触发真实服务商限流 - 生产环境别裸写定时器轮询发信,改用消息队列(如
redislist + worker)做节流和失败重试
真正难的不是拼出一封能发出去的邮件,而是让每封都稳定进收件箱——发信地址的域名信誉、HELO 声明、TLS 版本、甚至邮件正文里链接的跳转深度,都会影响最终投递结果。










