Parcourir la source

发送邮件(mail 包)

runningwater il y a 8 mois
Parent
commit
7452095a62
6 fichiers modifiés avec 154 ajouts et 0 suppressions
  1. 23 0
      config/mail.go
  2. 1 0
      go.mod
  3. 2 0
      go.sum
  4. 11 0
      pkg/mail/driver_interface.go
  5. 71 0
      pkg/mail/driver_smtp.go
  6. 46 0
      pkg/mail/mail.go

+ 23 - 0
config/mail.go

@@ -0,0 +1,23 @@
+package config
+
+import "github.com/runningwater/gohub/pkg/config"
+
+func init() {
+	config.Add("mail", func() map[string]any {
+		return map[string]any{
+
+			// 默认是 Mailhog 的配置
+			"smtp": map[string]any{
+				"host":     config.Env("MAIL_HOST", "localhost"),
+				"port":     config.Env("MAIL_PORT", 1025),
+				"username": config.Env("MAIL_USERNAME", ""),
+				"password": config.Env("MAIL_PASSWORD", ""),
+			},
+			// 默认发件人
+			"from": map[string]any{
+				"address": config.Env("MAIL_FROM_ADDRESS", "gohub@example.com"),
+				"name":    config.Env("MAIL_FROM_NAME", "Gohub"),
+			},
+		}
+	})
+}

+ 1 - 0
go.mod

@@ -6,6 +6,7 @@ require (
 	github.com/KenmyZhang/aliyun-communicate v0.0.0-20180308134849-7997edc57454
 	github.com/gin-gonic/gin v1.10.0
 	github.com/go-redis/redis v6.15.9+incompatible
+	github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible
 	github.com/mojocn/base64Captcha v1.3.8
 	github.com/spf13/cast v1.7.1
 	github.com/spf13/viper v1.20.1

+ 2 - 0
go.sum

@@ -71,6 +71,8 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD
 github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
 github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
 github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
+github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible h1:jdpOPRN1zP63Td1hDQbZW73xKmzDvZHzVdNYxhnTMDA=
+github.com/jordan-wright/email v4.0.1-0.20210109023952-943e75fe5223+incompatible/go.mod h1:1c7szIrayyPPB/987hsnvNzLushdWf4o/79s3P08L8A=
 github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
 github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
 github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=

+ 11 - 0
pkg/mail/driver_interface.go

@@ -0,0 +1,11 @@
+package mail
+
+// Driver 邮件驱动接口
+// 实现该接口后可通过配置切换不同的邮件发送服务
+type Driver interface {
+	// Send 发送邮件
+	// email 包含邮件内容
+	// config 驱动配置信息,需包含对应驱动的配置项
+	// 返回 bool 表示是否发送成功
+	Send(email Email, config map[string]string) bool
+}

+ 71 - 0
pkg/mail/driver_smtp.go

@@ -0,0 +1,71 @@
+package mail
+
+// Installation
+// go get github.com/jordan-wright/email
+
+// Note: Version > 1 of this library requires Go v1.5 or above.
+
+// If you need compatibility with previous Go versions, you can use the previous package at gopkg.in/jordan-wright/email.v1
+// Sending email using Gmail
+//
+// e := email.NewEmail()
+// e.From = "Jordan Wright <test@gmail.com>"
+// e.To = []string{"test@example.com"}
+// e.Bcc = []string{"test_bcc@example.com"}
+// e.Cc = []string{"test_cc@example.com"}
+// e.Subject = "Awesome Subject"
+// e.Text = []byte("Text Body is, of course, supported!")
+// e.HTML = []byte("<h1>Fancy HTML is supported, too!</h1>")
+// e.Send("smtp.gmail.com:587", smtp.PlainAuth("", "test@gmail.com", "password123", "smtp.gmail.com"))
+
+import (
+	"fmt"
+	"net/smtp"
+
+	emailPKG "github.com/jordan-wright/email"
+	"github.com/runningwater/gohub/pkg/logger"
+)
+
+// SMTP 实现 email.Driver 接口
+// 使用 github.com/jordan-wright/email 库实现 SMTP 协议邮件发送
+type SMTP struct{}
+
+// Send 发送邮件
+// 参数 config 需包含以下配置项:
+//
+//	host     - SMTP 服务器地址
+//	port     - SMTP 端口
+//	username - 认证用户名
+//	password - 认证密码
+//
+// 返回 bool 表示邮件是否成功投递到服务器
+func (s *SMTP) Send(email Email, config map[string]string) bool {
+	// 实现发送邮件的逻辑
+	e := emailPKG.NewEmail()
+	e.From = fmt.Sprintf("%s <%s>", email.From.Name, email.From.Address)
+	e.To = email.To
+	e.Bcc = email.Bcc
+	e.Cc = email.Cc
+	e.Subject = email.Subject
+	e.Text = email.Text
+	e.HTML = email.HTML
+
+	logger.DebugJSON("发送邮件", "发送详情", e)
+
+	if err := e.Send(
+		fmt.Sprintf("%v:%v", config["host"], config["port"]),
+		smtp.PlainAuth(
+			"",
+			config["username"],
+			config["password"],
+			config["host"],
+		),
+	); err != nil {
+		logger.ErrorString("发送邮件", "发送邮件失败", err.Error())
+		return false
+	}
+
+	// 成功时记录简略日志,避免泄露敏感内容
+	logger.DebugString("发送邮件", "投递状态", "服务器已接收邮件")
+	return true
+}

+ 46 - 0
pkg/mail/mail.go

@@ -0,0 +1,46 @@
+package mail
+
+import "sync"
+
+// To 收件人邮箱列表
+type To []string
+
+// From 发件人信息
+type From struct {
+	Address string // 邮箱地址
+	Name    string // 发件人名称(可选)
+}
+
+// Email 邮件内容结构
+type Email struct {
+	From        From     // 发件人
+	To          To       // 主送人
+	Bcc         To       // 密送人
+	Cc          To       // 抄送人
+	Subject     string   // 邮件主题
+	Text        []byte   // 纯文本正文
+	HTML        []byte   // HTML格式正文
+	Attachments []string // 附件路径列表
+}
+
+// Mailer 邮件发送器
+type Mailer struct {
+	Driver Driver // 邮件驱动实现(SMTP/Mailgun等)
+}
+
+var once sync.Once
+var mailer *Mailer
+
+// NewMailer 创建邮件发送器单例
+func NewMailer() *Mailer {
+	once.Do(func() {
+		mailer = &Mailer{}
+	})
+	return mailer
+}
+
+// Send 使用配置的驱动发送邮件
+// 返回值 bool 表示是否发送成功
+func (m *Mailer) Send(email Email, config map[string]string) bool {
+	return m.Driver.Send(email, config)
+}