
在 go 中使用标准库 `net/smtp` 发送邮件时,仅靠 `client.mail()` 传入带名称的邮箱会导致 501 错误;正确做法是将“显示名称 + 邮箱”格式写入邮件正文头部的 `from` 字段,而 `client.mail()` 参数必须为纯邮箱地址。
go 标准库 net/smtp 的 Client.mail(from String) 方法仅接受 RFC 5321 兼容的纯邮箱地址(如 [email protected]),不支持 “Name
真正控制收件端显示名称的,是邮件内容头部(MIME header)中的 From: 字段。该字段遵循 RFC 5322,允许使用带引号的显示名语法:
From: Sandy Sender <[email protected]>
✅ 正确实现步骤如下:
- Client.Mail() 传纯邮箱地址(用于 SMTP 协议层身份验证与投递路由);
- 在构造邮件正文时,在头部显式设置 From: 行,格式为 “显示名 “;
- 确保整个邮件符合 MIME 格式(含空行分隔头与体、正确编码等)。
✅ 手动构造示例(标准库)
package main import ( "fmt" "net/smtp" "strings" ) func main() { auth := smtp.PlainAuth("", "user@example.com", "app-password", "smtp.example.com") to := []string{"[email protected]"} from := "[email protected]" // ← 仅邮箱!用于 Mail() fromHeader := "Sandy Sender <" + from + ">" // ← 带名格式!用于 From: 头部 msg := fmt.Sprintf( "From: %srn"+ "To: %srn"+ "Subject: Hello from Go!rn"+ "MIME-Version: 1.0rn"+ "Content-Type: text/plain; charset=utf-8rn"+ "rn"+ "This is the body of the message.", fromHeader, strings.Join(to, ", "), ) err := smtp.SendMail( "smtp.example.com:587", auth, from, // ← 关键:纯邮箱 to, []byte(msg), ) if err != nil { panic(err) } }
✅ 推荐方案:使用 gomail(更安全、更简洁)
手动拼接邮件头易出错(如编码缺失、换行符不规范)。推荐使用成熟封装库 gomail(v2),它自动处理 RFC 合规性、UTF-8 编码、MIME 分隔等细节:
package main import ( "gopkg.in/gomail.v2" ) func main() { m := gomail.NewMessage() m.SetAddressHeader("From", "[email protected]", "Sandy Sender") m.SetAddressHeader("To", "[email protected]") m.SetHeader("Subject", "Hello!") m.SetBody("text/plain", "This is the body of the message.") d := gomail.NewPlainDialer("smtp.example.com", 587, "user@example.com", "app-password") if err := d.DialAndSend(m); err != nil { panic(err) } }
⚠️ 注意事项: 显示名(如 “Sandy Sender”)若含非 ASCII 字符(如中文),gomail 会自动进行 B 类型 MIME 编码(如 =?UTF-8?B?5byg5LiJ?=),而手动拼接需自行调用 mime.BEncoding.Encode(); SMTP 认证凭据建议使用应用专用密码(如 Gmail App Password),避免主密码泄露; 生产环境务必启用 TLS(gomail.NewDialer 支持 TLSConfig),禁用明文传输。
通过分离「协议层发件地址」与「展示层发件人信息」,即可优雅实现专业邮件署名效果。