Beego 中 SMTP 邮件服务需在 conf/app.conf 按 runmode 分环境配置 host/port/user/pass,密码用 DefaultString 防 panic,生产环境应从 os.Getenv 注入;邮件模板用 template.ParseFiles 显式加载并传 map 数据渲染,不可依赖 c.Data 或自动路径查找,且须确保字段可导出、扩展名限 .html/.tpl。

Beego 中如何配置 SMTP 邮件服务
Beego 本身不内置邮件发送模块,得自己集成 net/smtp 或第三方库(如 gomail),但关键在于配置项管理与调用时机。常见错误是把 SMTP 参数硬编码在控制器里,导致无法切换环境(dev/test/prod)。
推荐做法:统一在 conf/app.conf 中定义 SMTP 配置,并按 runmode 区分:
smtp_host = "smtp.gmail.com" smtp_port = 587 smtp_user = "your@email.com" smtp_pass = "app-specific-password" [prod] smtp_host = "smtp.qiye.aliyun.com" smtp_port = 465 smtp_user = "notify@company.com"
在代码中读取时用 beego.AppConfig.String("smtp_host"),别直接写死字符串;密码类字段务必用 DefaultString 做 fallback,避免空值 panic。
- 端口必须匹配协议:587(STARTTLS)或 465(SSL),
net/smtp默认不支持自动协商 - Gmail 等平台需开启“应用专用密码”,不能用账户登录密码
- 生产环境禁用明文
smtp_pass,应从环境变量注入(os.Getenv("SMTP_PASS"))再覆盖配置
邮件内容用 Beego 模板渲染是否可行
可行,但不是直接调 c.Render() —— 邮件模板和 HTTP 响应模板共用 html/template 引擎,但路径、数据上下文、输出目标完全不同。
核心区别:
- 模板路径需显式指定,不能依赖
views/{controller}/{method}.html自动查找规则 - 数据传入用普通
map[string]interface{},不是c.Data(因为没 controller 上下文) - 渲染后得到的是
string或[]byte,要手动塞进邮件正文字段
示例片段:
tmpl, _ := template.ParseFiles("views/email/welcome.html")
var buf bytes.Buffer
tmpl.Execute(&buf, map[string]interface{}{
"Name": "张三",
"Token": "abc123",
})
body := buf.String() // 这才是发邮件时的正文
注意:views/ 是默认路径,若改过 viewspath,这里必须同步调整;模板里仍用 {{.Name}},不是 {{.Data.Name}}。
模板里调用 .Now 或自定义函数报错怎么办
Beego 默认模板函数集很精简,now、date、htmlEscape 这些都不自带。直接写 {{.Now}} 会报 template: can't evaluate field Now。
解决方式只有两个:
- 在传入模板的 data map 里预计算好时间:
"Now": time.Now().Format("2006-01-02") - 全局注册自定义函数,放在
main.go的beego.Run()之前:
beego.AddFuncMap("now", func() time.Time { return time.Now() })
beego.AddFuncMap("formatDate", func(t time.Time, layout string) string {
return t.Format(layout)
})
之后模板中就能写 {{now | formatDate "2006-01-02"}}。注意函数名必须小写(Go 模板限制),且参数类型要严格匹配,否则运行时报 invalid value。
为什么邮件模板里 {{.User.Email}} 渲染为空
最常见原因是传入的数据结构层级和模板访问路径不一致。Beego 模板里的 . 指向你传进去的那个顶层 map 或 struct,不是整个 controller 实例。
比如你写了:
c.Data["User"] = userStruct // userStruct.Email = "a@b.com" // 错误:试图在邮件模板里用 c.Data —— 邮件模板根本不走 c.Data
正确做法是构造干净的 map:
data := map[string]interface{}{
"User": map[string]string{"Email": "a@b.com"},
}
tmpl.Execute(&buf, data)
此时 {{.User.Email}} 才能命中。如果传的是 struct,确保字段首字母大写(Go 可导出要求),且没加 json:"email" tag 干扰模板反射。
容易被忽略的一点:模板文件扩展名必须是 Beego 明确支持的(.html、.tpl),.gohtml 虽然 Go 标准库支持,但 Beego 不识别,会静默失败。


















