128 lines
3.6 KiB
Go
128 lines
3.6 KiB
Go
// with_env 展示如何通过环境变量管理通道凭据(避免把密钥写死在代码里)。
|
|||
|
|
//
|
||
|
|
// 适用场景:已有多个通道的凭据(SMTP / 阿里云 / AWS SES / Mailgun),
|
||
|
|
// 希望在程序启动时从环境变量读取配置,注册到 Manager 统一管理。
|
||
|
|
//
|
||
|
|
// 怎么运行:
|
||
|
|
// 1. 复制 .env.example 为 .env(或直接设置下方环境变量)
|
||
|
|
// 2. 安装 dotenv 依赖:go get github.com/joho/godotenv
|
||
|
|
// 3. 设置好至少一个通道的凭据后执行:go run main.go
|
||
|
|
package main
|
||
|
|
|
||
|
|
import (
|
||
|
|
"context"
|
||
|
|
"fmt"
|
||
|
|
"log"
|
||
|
|
"os"
|
||
|
|
|
||
|
|
"code.yun.ink/pkg/mailx"
|
||
|
|
"code.yun.ink/pkg/mailx/aliyun"
|
||
|
|
"code.yun.ink/pkg/mailx/aws"
|
||
|
|
"code.yun.ink/pkg/mailx/mailgun"
|
||
|
|
"code.yun.ink/pkg/mailx/smtp"
|
||
|
|
|
||
|
|
"github.com/joho/godotenv" // 读取 .env 文件(可选)
|
||
|
|
)
|
||
|
|
|
||
|
|
// buildSenders 从环境变量读取凭据,返回已配置好的通道列表。
|
||
|
|
// 只返回凭据齐全的通道,未配置的通道直接跳过,方便按需启用。
|
||
|
|
func buildSenders() []mailx.Sender {
|
||
|
|
var senders []mailx.Sender
|
||
|
|
|
||
|
|
// --- SMTP ---
|
||
|
|
if os.Getenv("SMTP_HOST") != "" {
|
||
|
|
senders = append(senders, smtp.New(smtp.Config{
|
||
|
|
Host: os.Getenv("SMTP_HOST"),
|
||
|
|
Port: atoi(os.Getenv("SMTP_PORT"), 465),
|
||
|
|
User: os.Getenv("SMTP_USER"),
|
||
|
|
Password: os.Getenv("SMTP_PASSWORD"),
|
||
|
|
From: os.Getenv("SMTP_FROM"),
|
||
|
|
}))
|
||
|
|
}
|
||
|
|
|
||
|
|
// --- 阿里云邮件推送 ---
|
||
|
|
if os.Getenv("ALIYUN_ACCESS_KEY_ID") != "" {
|
||
|
|
senders = append(senders, aliyun.New(aliyun.Config{
|
||
|
|
AccessKeyID: os.Getenv("ALIYUN_ACCESS_KEY_ID"),
|
||
|
|
AccessKeySecret: os.Getenv("ALIYUN_ACCESS_KEY_SECRET"),
|
||
|
|
AccountName: os.Getenv("ALIYUN_ACCOUNT_NAME"),
|
||
|
|
Endpoint: os.Getenv("ALIYUN_ENDPOINT"), // 可选,默认 dm.aliyuncs.com
|
||
|
|
}))
|
||
|
|
}
|
||
|
|
|
||
|
|
// --- AWS SES ---
|
||
|
|
if os.Getenv("AWS_ACCESS_KEY_ID") != "" {
|
||
|
|
senders = append(senders, aws.New(aws.Config{
|
||
|
|
AccessKeyID: os.Getenv("AWS_ACCESS_KEY_ID"),
|
||
|
|
AccessKeySecret: os.Getenv("AWS_ACCESS_KEY_SECRET"),
|
||
|
|
Region: os.Getenv("AWS_REGION"),
|
||
|
|
Sender: os.Getenv("AWS_SENDER"),
|
||
|
|
}))
|
||
|
|
}
|
||
|
|
|
||
|
|
// --- Mailgun ---
|
||
|
|
if os.Getenv("MAILGUN_API_KEY") != "" {
|
||
|
|
senders = append(senders, mailgun.New(mailgun.Config{
|
||
|
|
APIKey: os.Getenv("MAILGUN_API_KEY"),
|
||
|
|
Domain: os.Getenv("MAILGUN_DOMAIN"),
|
||
|
|
Sender: os.Getenv("MAILGUN_SENDER"),
|
||
|
|
}))
|
||
|
|
}
|
||
|
|
|
||
|
|
return senders
|
||
|
|
}
|
||
|
|
|
||
|
|
func main() {
|
||
|
|
ctx := context.Background()
|
||
|
|
|
||
|
|
// 可选:加载 .env 文件(没有 .env 时静默忽略,改用系统环境变量)
|
||
|
|
_ = godotenv.Load()
|
||
|
|
|
||
|
|
senders := buildSenders()
|
||
|
|
if len(senders) == 0 {
|
||
|
|
log.Fatal("no channel configured, please set env vars (see .env.example)")
|
||
|
|
}
|
||
|
|
|
||
|
|
// 注册到 Manager,第一个注册的成为默认通道
|
||
|
|
mgr := mailx.NewManager()
|
||
|
|
for _, s := range senders {
|
||
|
|
if err := mgr.Register(s); err != nil {
|
||
|
|
log.Fatalf("register %s: %v", s.Name(), err)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
log.Printf("registered channels: %v (default: %s)", mgr.Names(), mgr.Default())
|
||
|
|
|
||
|
|
msg := mailx.NewMessage().
|
||
|
|
From(firstNonEmpty(os.Getenv("FROM_ADDR"), os.Getenv("SMTP_FROM"), os.Getenv("AWS_SENDER"), os.Getenv("MAILGUN_SENDER"))).
|
||
|
|
To(os.Getenv("TO_ADDR")).
|
||
|
|
Subject("hello from mailx (env config)").
|
||
|
|
Text("This email is sent using env-var configured channel.").
|
||
|
|
Build()
|
||
|
|
|
||
|
|
// 用默认通道发送
|
||
|
|
if err := mgr.Send(ctx, msg); err != nil {
|
||
|
|
fmt.Println("send failed:", err)
|
||
|
|
return
|
||
|
|
}
|
||
|
|
fmt.Println("send success")
|
||
|
|
}
|
||
|
|
|
||
|
|
// atoi 解析端口,失败时返回默认值
|
||
|
|
func atoi(s string, def int) int {
|
||
|
|
n := 0
|
||
|
|
if _, err := fmt.Sscanf(s, "%d", &n); err != nil || n <= 0 {
|
||
|
|
return def
|
||
|
|
}
|
||
|
|
return n
|
||
|
|
}
|
||
|
|
|
||
|
|
// firstNonEmpty 返回第一个非空字符串
|
||
|
|
func firstNonEmpty(vals ...string) string {
|
||
|
|
for _, v := range vals {
|
||
|
|
if v != "" {
|
||
|
|
return v
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return ""
|
||
|
|
}
|