112 lines
3.8 KiB
Go
112 lines
3.8 KiB
Go
// 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)
|
|
}
|
|
}
|