beego.SendMail函数默认依赖本地sendmail命令,不支持SMTP协议、TLS/SSL、OAuth2等现代特性,且在容器、云服务器及Windows环境下普遍失效,故必须替换为gomail.v2等SMTP方案。

Beego 自带的 beego.SendMail 函数能发邮件,但默认依赖系统 sendmail 命令,线上环境基本不可用;实际项目中必须改用 SMTP 方式,且需手动配置 gopkg.in/gomail.v2 或原生 net/smtp。
为什么不能直接用 beego.SendMail
这个函数本质是调用本地 sendmail 二进制,启动子进程发送,不走网络协议。容器部署、云服务器(如阿里云 ECS 默认禁用 25 端口)、Windows 环境下几乎必然失败,错误常表现为:exec: "sendmail": executable file not found in $PATH 或连接超时。
- 它不支持 TLS/SSL、OAuth2、自定义端口等现代 SMTP 必需特性
- 无法获取详细错误(比如认证失败、被拒收),日志只显示“send failed”
- Beego 2.x 已标记该函数为 deprecated,后续版本可能移除
推荐方案:用 gomail.v2 封装成 Beego 的 service
比原生 net/smtp 更简洁,自动处理 MIME、附件、HTML 正文、编码,且与 Beego 生命周期兼容。建议在 models/ 或 services/ 下新建 mail.go:
package services
import (
"gopkg.in/gomail.v2"
)
type MailService struct {
dialer *gomail.Dialer
}
func NewMailService(host string, port int, user, password string) *MailService {
return &MailService{
dialer: gomail.NewDialer(host, port, user, password),
}
}
func (m *MailService) Send(to, subject, body string) error {
msg := gomail.NewMessage()
msg.SetHeader("From", m.dialer.Username)
msg.SetHeader("To", to)
msg.SetHeader("Subject", subject)
msg.SetBody("text/plain", body)
return m.dialer.DialAndSend(msg)
}
- 注意端口选择:
587(STARTTLS)或465(SMTPS),避免用 25(多数云厂商拦截) - Gmail 需开启「App Password」,不能用账户密码;QQ 邮箱需在设置里生成独立密码
- 若发 HTML 邮件,把
msg.SetBody("text/plain", ...)换成msg.AddAlternative("text/html", htmlBody)
在 Controller 中调用并处理常见错误
不要在每次请求里 new 一个 MailService,应作为单例注入或全局初始化。例如在 main.go 初始化后存入 beego.AppConfig 或自定义全局变量:
var MailSvc *services.MailService
func init() {
MailSvc = services.NewMailService(
beego.AppConfig.String("smtp::host"),
beego.AppConfig.Int("smtp::port"),
beego.AppConfig.String("smtp::user"),
beego.AppConfig.String("smtp::password"),
)
}
Controller 中使用:
func (c *MainController) SendNotify() {
err := MailSvc.Send("user@example.com", "订单通知", "您的订单已创建")
if err != nil {
beego.Error("邮件发送失败:", err)
c.Data["json"] = map[string]interface{}{"success": false, "msg": "通知发送延迟,请稍后查看邮箱"}
c.ServeJSON()
return
}
c.Data["json"] = map[string]interface{}{"success": true}
c.ServeJSON()
}
- 典型错误:
dial tcp: lookup smtp.qq.com: no such host→ DNS 解析失败,检查容器 / 服务器网络 -
535 5.7.8 Error: authentication failed→ 用户名密码错误,或未开启 SMTP 服务 -
452 4.7.1 Requested action not taken: too many recipients→ 单次发送超过服务商限制(如 QQ 邮箱限 200 收件人)
SMTP 配置项(conf/app.conf)容易漏掉 smtp:: 前缀,导致 AppConfig.String 返回空字符串——这是最常被忽略的细节,务必核对 key 名和类型转换是否匹配。


















