fix(email):修复邮件相关功能

This commit is contained in:
chengqian committed 2026-08-31 15:59:22 +08:00
1 parent 958f6c4d75
commit 1f07fae1c2
4 files changed
+34 -11

No files matched your search

+21 -2
View File
@@ -4,11 +4,13 @@ import (
"bytes"
"context"
"crypto/tls"
"github.com/qianfree/team-api/internal/dao"
"html/template"
"net/mail"
"strings"
"time"
"github.com/qianfree/team-api/internal/dao"
"github.com/gogf/gf/v2/errors/gerror"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime"
@@ -23,6 +25,7 @@ type EmailConfig struct {
Username string
Password string
From string
FromName string // 发件人显示名,收件人邮件列表里看到的名字;为空时只显示邮箱地址
UseTLS bool
}
@@ -121,7 +124,17 @@ func (s *BasicEmailSender) SendTemplate(ctx context.Context, to, templateCode st
// sendWithRetry performs the actual SMTP send.
func (s *BasicEmailSender) sendWithRetry(ctx context.Context, msg *EmailMessage, attempt int) error {
m := gomail.NewMessage()
m.SetHeader("From", s.config.From)
// 发件人显示名:SetAddressHeader 会按 RFC 5322 拼成 "aifree" <system@mail.aifree.com>,
// 名称含中文时自动做 RFC 2047 编码;FromName 为空时退化为纯地址。
// From 若已配成 "名称 <地址>" 形式,先拆出地址避免二次包装。
fromAddr, fromName := s.config.From, s.config.FromName
if parsed, err := mail.ParseAddress(fromAddr); err == nil {
fromAddr = parsed.Address
if fromName == "" {
fromName = parsed.Name
}
}
m.SetAddressHeader("From", fromAddr, fromName)
m.SetHeader("To", msg.To)
m.SetHeader("Subject", msg.Subject)
@@ -205,6 +218,7 @@ func EmailConfigFromOptions(ctx context.Context) (*EmailConfig, error) {
Username: Config().GetString(ctx, "email_smtp_username"),
Password: Config().GetString(ctx, "email_smtp_password"),
From: Config().GetString(ctx, "email_smtp_from"),
FromName: Config().GetString(ctx, "email_smtp_from_name"),
UseTLS: Config().GetBool(ctx, "email_smtp_tls"),
}
@@ -212,6 +226,11 @@ func EmailConfigFromOptions(ctx context.Context) (*EmailConfig, error) {
return nil, gerror.New("email SMTP config not set (email_smtp_host, email_smtp_from)")
}
// 未单独配置发件人名称时回落到站点名称,避免收件人只看到邮箱地址的本地部分
if cfg.FromName == "" {
cfg.FromName = Config().GetString(ctx, "site_name")
}
if cfg.Port == 0 {
cfg.Port = 587
}
@@ -107,6 +107,8 @@ var Registry = []SettingDef{
Label: "SMTP 密码", Sensitive: true},
{Key: "email_smtp_from", Type: SettingTypeString, Default: "", Category: "email",
Label: "发件人地址", Description: "格式: noreply@example.com"},
{Key: "email_smtp_from_name", Type: SettingTypeString, Default: "", Category: "email",
Label: "发件人名称", Description: "收件人看到的发件人显示名,如 aifree;留空则使用站点名称"},
{Key: "email_smtp_tls", Type: SettingTypeBool, Default: "true", Category: "email",
Label: "启用 TLS", Description: "587/465 端口建议开启"},
+8 -9
View File
@@ -95,15 +95,14 @@ func dispatchAlertNotifications(ctx context.Context, rule map[string]any, eventI
// sendAlertEmailToAdmins sends alert email to specified admin users.
func sendAlertEmailToAdmins(ctx context.Context, adminIDs []int64, subject, body string) {
// Create email sender from config
sender := common.NewEmailSender(&common.EmailConfig{
Host: g.Cfg().MustGet(ctx, "email.smtp.host").String(),
Port: g.Cfg().MustGet(ctx, "email.smtp.port").Int(),
Username: g.Cfg().MustGet(ctx, "email.smtp.username").String(),
Password: g.Cfg().MustGet(ctx, "email.smtp.password").String(),
From: g.Cfg().MustGet(ctx, "email.smtp.from").String(),
UseTLS: g.Cfg().MustGet(ctx, "email.smtp.port").Int() == 587 || g.Cfg().MustGet(ctx, "email.smtp.port").Int() == 465,
})
// 与其余邮件链路统一走设置注册表(管理后台「邮件配置」),
// 而非 config.yaml 的 email.smtp.*(该配置段不存在,会读出空值导致告警邮件必然发送失败)
cfg, err := common.EmailConfigFromOptions(ctx)
if err != nil {
g.Log().Warningf(ctx, "send alert email: %v", err)
return
}
sender := common.NewEmailSender(cfg)
for _, adminID := range adminIDs {
type adminUser struct {
@@ -37,6 +37,9 @@ const values = useFormValues()
<AFormItem label="发件人地址" help="格式: noreply@example.com">
<AInput v-model="values['email_smtp_from']" placeholder="noreply@example.com" />
</AFormItem>
<AFormItem label="发件人名称" help="收件人看到的发件人显示名,留空则使用站点名称">
<AInput v-model="values['email_smtp_from_name']" placeholder="aifree" />
</AFormItem>
<div class="switch-row">
<span class="switch-label">启用 TLS</span>
<span class="switch-desc">587/465 端口建议开启</span>