更新
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
// 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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user