
Go 使用 smtp.SendMail 发送邮件时,若仅设置 envelope-to(传输层收件人),而未在邮件正文头部显式声明 To: 等 MIME 头字段,会导致收件箱中显示 “Undisclosed recipients:;” —— 本文详解如何构造符合 RFC 5322 标准的完整邮件头,确保 To、From、Subject 等字段正确呈现。
go 使用 `smtp.sendmail` 发送邮件时,若仅设置 envelope-to(传输层收件人),而未在邮件正文头部显式声明 `to:` 等 mime 头字段,会导致收件箱中显示 “undisclosed recipients:;” —— 本文详解如何构造符合 rfc 5322 标准的完整邮件头,确保 `to`、`from`、`subject` 等字段正确呈现。
在 Go 中通过 net/smtp 发送邮件,常被忽略的关键点是:邮件传输层(envelope)与邮件内容层(MIME headers)是两个独立概念。smtp.SendMail 的第四个参数 to []string 仅用于 SMTP 协议的 RCPT TO 命令(即投递路由),它不会自动写入邮件正文的 To: 头部。而邮箱客户端(如 Outlook、Gmail)显示的“收件人”,完全取决于邮件正文中 To: 这一 MIME 头字段的值 —— 若缺失或为空,多数客户端将降级显示为 Undisclosed recipients:;。
要解决该问题,必须手动构建符合规范的邮件头(headers),并严格遵循电子邮件标准:
- 所有头字段行必须以 \r\n 结尾(而非 \n);
- 头部与邮件正文之间需用空行(\r\n\r\n)分隔;
- To、From、Subject 等字段应作为独立头行写入;
- 地址建议使用标准格式,例如 "Name
" 或 。
以下是一个生产就绪的示例代码:
package main
import (
"bytes"
"fmt"
"net/smtp"
)
func sendEmail() error {
from := "sender@example.com"
to := []string{"recipient1@example.com", "recipient2@example.com"}
subject := "测试邮件主题"
body := "这是一封来自 Go 的 HTML 邮件。\n\n祝好!"
// 构建 MIME 头部(注意:全部使用 \r\n)
headers := map[string]string{
"From": fmt.Sprintf("<%s>", from),
"To": fmt.Sprintf("<%s>", to[0]), // 或 join 多个地址:strings.Join(to, ", ")
"Subject": subject,
"MIME-Version": "1.0",
"Content-Type": `text/plain; charset="UTF-8"`,
}
var msg bytes.Buffer
for key, value := range headers {
msg.WriteString(fmt.Sprintf("%s: %s\r\n", key, value))
}
msg.WriteString("\r\n") // 空行分隔头部与正文
msg.WriteString(body)
// 发送(注意:envelope-to 仍需传入 to 列表,用于实际投递)
auth := smtp.PlainAuth("", "", "", "localhost") // 本地 Postfix 通常无需认证
return smtp.SendMail("localhost:25", auth, from, to, msg.Bytes())
}✅ 关键注意事项:
- 若需支持多个收件人并在 To: 中全部显示,可将 to 切片用英文逗号连接:strings.Join(to, ", "),并确保每个地址格式合法;
- 对于 HTML 邮件,将 Content-Type 改为 text/html; charset="UTF-8",并确保 body 是合法 HTML 片段;
- 生产环境强烈建议使用成熟邮件库替代手写头,例如:
- gomail.v2(轻量、API 清晰);
- mailgun-go(对接 Mailgun 服务);
- go-mail(现代、支持附件/嵌入图片/模板);
- net/mail 包可用于解析和验证邮箱地址(如 mail.ParseAddress),但不负责构造发送邮件;
- net/textproto 提供底层文本协议工具(如 CanonicalMIMEHeaderKey),适合高级定制,一般场景无需直接使用。
总结:SMTP envelope 决定“邮件发给谁”,MIME headers 决定“邮件显示给谁看”。二者必须协同设置,缺一不可。始终显式构造 To:、From:、Subject: 等头部,并坚持使用 \r\n 换行,即可彻底避免 Undisclosed recipients 问题。










