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

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...)
}