You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
94 lines
2.3 KiB
94 lines
2.3 KiB
package email
|
|
|
|
import (
|
|
"errors"
|
|
"sync"
|
|
)
|
|
|
|
/*
|
|
系统描述:邮件系统,现支持qq邮箱以及gmail邮箱的邮件发送
|
|
*/
|
|
type (
|
|
ISys interface {
|
|
SendMail(title, content string, to ...string) error
|
|
SendMailForFile(title string, content string, filepath string, filename string, to ...string) (err error)
|
|
}
|
|
)
|
|
|
|
// defsys 由 OnInit(启动) 与 Reload(运行时热更) 写、SendMail* 读,故必须加锁:
|
|
// 热重载会整个换掉客户端(SMTP 的 *Email 与 Resend 的 *Resend 是不同具体类型),
|
|
// 无锁并发读写接口值是 data race。
|
|
var (
|
|
mu sync.RWMutex
|
|
defsys ISys
|
|
)
|
|
|
|
var errNotInit = errors.New("email 系统未初始化")
|
|
|
|
func get() ISys {
|
|
mu.RLock()
|
|
defer mu.RUnlock()
|
|
return defsys
|
|
}
|
|
|
|
func set(sys ISys) {
|
|
mu.Lock()
|
|
defsys = sys
|
|
mu.Unlock()
|
|
}
|
|
|
|
// OnInit 配置缺失/不合法时返回 error 而非 panic——邮件属可选能力,缺配置应由调用方降级
|
|
// (未初始化时 SendMail* 返回 errNotInit),后续可经 console 配好后 Reload 热生效。
|
|
func OnInit(config map[string]interface{}, option ...Option) (err error) {
|
|
options, err := newOptionsChecked(config, option...)
|
|
if err != nil {
|
|
return
|
|
}
|
|
sys, err := newSys(options)
|
|
if err != nil {
|
|
return
|
|
}
|
|
set(sys)
|
|
return
|
|
}
|
|
|
|
// Reload 运行时热替换邮件客户端(console 后台改配置后由业务侧调用)。
|
|
// 与 OnInit 的关键差别:配置不合法时返回 error 而非 panic,且**保留原客户端不动**,
|
|
// 保证一次误保存不会让线上服务失去发信能力。
|
|
func Reload(config map[string]interface{}, option ...Option) error {
|
|
options, err := newOptionsChecked(config, option...)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
sys, err := newSys(options)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
set(sys)
|
|
return nil
|
|
}
|
|
|
|
func NewSys(option ...Option) (sys ISys, err error) {
|
|
options, err := newOptionsByOption(option...)
|
|
if err != nil {
|
|
return
|
|
}
|
|
sys, err = newSys(options)
|
|
return
|
|
}
|
|
|
|
func SendMail(title, content string, to ...string) error {
|
|
sys := get()
|
|
if sys == nil {
|
|
return errNotInit
|
|
}
|
|
return sys.SendMail(title, content, to...)
|
|
}
|
|
|
|
func SendMailForFile(title, content string, filepath string, filename string, to ...string) error {
|
|
sys := get()
|
|
if sys == nil {
|
|
return errNotInit
|
|
}
|
|
return sys.SendMailForFile(title, content, filepath, filename, to...)
|
|
}
|
|
|