// 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(`"通知中心" `). // 发件人带显示名 To("user@example.com"). Subject("生产环境告警"). Text("这是一封告警邮件,请及时处理。"). HTML(`

磁盘使用率超过 90%

`). InlineImageBytes("chart1", "chart.png", []byte{0x89, 0x50, 0x4e, 0x47}). // 内嵌图片,cid:chart1 对应 Header("X-Mailer", "mailx"). // 自定义邮件头 Header("List-Unsubscribe", ""). // 退订头(营销邮件合规) 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": "welcome", }) if err == nil { _ = mgr.Send(ctx, m) } }