Files
mailx/examples/advanced/main.go
T

112 lines
3.8 KiB
Go
Raw Normal View History

2026-08-15 01:38:05 +08:00
// advanced 展示生产环境常用的一些进阶能力。
//
// 覆盖以下内容:
// 1. 同一通道类型(smtp)注册多份不同配置(主备切换)
// 2. 遍历当前注册的通道实例信息
// 3. 注入自定义 Logger(日志可插拔)
// 4. 设置通道超时,防止发送阻塞
// 5. 内嵌图片 + HTML 邮件
// 6. 用 FromMap 从 map 快捷构建消息
// 7. 按错误类型精确处理(errors.Is)
//
// 怎么运行:设置好下方配置后执行:go run main.go
package main
import (
"context"
"errors"
"fmt"
"log"
"time"
"code.yun.ink/pkg/mailx"
"code.yun.ink/pkg/mailx/smtp"
)
// appLogger 一个简单的 Logger 实现(也可接入 zap/logrus)。
// 生产环境建议实现 Debugf/Infof/Warnf/Errorf 四个方法,用于观测发送过程。
type appLogger struct{}
func (appLogger) Debugf(_ context.Context, format string, args ...any) {
log.Printf("[debug] "+format, args...)
}
func (appLogger) Infof(_ context.Context, format string, args ...any) {
log.Printf("[info] "+format, args...)
}
func (appLogger) Warnf(_ context.Context, format string, args ...any) {
log.Printf("[warn] "+format, args...)
}
func (appLogger) Errorf(_ context.Context, format string, args ...any) {
log.Printf("[error] "+format, args...)
}
func main() {
ctx := context.Background()
mgr := mailx.NewManager()
mgr.SetLogger(appLogger{}) // 注入全局 Logger
// ===== 1. 同一通道类型注册多份配置(主备切换) =====
_ = mgr.RegisterNamed("smtp-main", smtp.New(smtp.Config{
Host: "smtp.qq.com", Port: 465, User: "a@qq.com", Password: "main-code",
Timeout: 10 * time.Second, // ===== 4. 通道超时,防止发送阻塞 =====
}))
_ = mgr.RegisterNamed("smtp-backup", smtp.New(smtp.Config{
Host: "smtp.163.com", Port: 465, User: "a@163.com", Password: "backup-code",
Timeout: 10 * time.Second,
}))
_ = mgr.SetDefault("smtp-main") // 默认用主通道
// ===== 2. 遍历当前注册的通道实例信息 =====
for _, info := range mgr.Senders() {
fmt.Printf("sender instance: name=%s type=%s\n", info.Name, info.Type)
}
// ===== 5. 内嵌图片 + HTML 邮件 =====
msg := mailx.NewMessage().
From(`"通知中心" <a@qq.com>`). // 发件人带显示名
To("user@example.com").
Subject("生产环境告警").
Text("这是一封告警邮件,请及时处理。").
HTML(`<h2>磁盘使用率超过 90%</h2><img src="cid:chart1">`).
InlineImageBytes("chart1", "chart.png", []byte{0x89, 0x50, 0x4e, 0x47}). // 内嵌图片,cid:chart1 对应
Header("X-Mailer", "mailx"). // 自定义邮件头
Header("List-Unsubscribe", "<https://example.com/unsub>"). // 退订头(营销邮件合规)
Build()
// ===== 3. 用默认通道发送(自动注入 Logger) =====
if err := mgr.Send(ctx, msg); err != nil {
fmt.Println("main send failed:", err)
}
// ===== 7. 错误类型精确处理:主通道失败自动切换备通道 =====
err := mgr.SendWith(ctx, "smtp-main", msg)
if err != nil {
// 发送失败(如网络/认证)属于 ErrSendFailed,而非配置/消息问题
if errors.Is(err, mailx.ErrSendFailed) {
fmt.Println("main failed, switching to backup:", err)
if err2 := mgr.SendWith(ctx, "smtp-backup", msg); err2 != nil {
fmt.Println("backup send failed:", err2)
return
}
} else if errors.Is(err, mailx.ErrInvalidMessage) {
fmt.Println("message invalid:", err) // 消息本身有问题,重试无意义
return
} else {
fmt.Println("send error:", err)
}
}
// ===== 6. 用 FromMap 从 map 快捷构建消息(适合接入 HTTP 请求体) =====
m, err := mailx.FromMap(map[string]any{
"from": "a@qq.com",
"to": "user@example.com, admin@example.com",
"subject": "welcome",
"text": "hi",
"html": "<b>welcome</b>",
})
if err == nil {
_ = mgr.Send(ctx, m)
}
}