
在 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: %s\r\n"+
"To: %s\r\n"+
"Subject: Hello from Go!\r\n"+
"MIME-Version: 1.0\r\n"+
"Content-Type: text/plain; charset=utf-8\r\n"+
"\r\n"+
"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),禁用明文传输。
通过分离「协议层发件地址」与「展示层发件人信息」,即可优雅实现专业邮件署名效果。










