@ -1,200 +0,0 @@
package emailsender
import (
"net/mail"
"regexp"
"strings"
"time"
"qoobing.com/gomod/email"
"qoobing.com/gomod/email/smtp"
"qoobing.com/gomod/log"
)
// ///////////////////////////////////////
// 发送器接口
// ///////////////////////////////////////
type Sender interface {
Send ( to string , name , body string ) error
SenderType ( ) string
SenderSupportAddressType ( ) string
}
type Config struct {
Id string ` toml:"id" ` //id
Type string ` toml:"type" ` //必选,发送器类型
Smtp string ` toml:"smtp" ` //必选, SMTP服务器地址( 含端口)
From string ` toml:"from" ` //必选,发件人
DryRun bool ` toml:"dryrun" ` //可选,只执行发送流程,但不真实发送
SmtpUser string ` toml:"smtpuser" ` //可选, SMTP授权人地址, 默认时从from中取
SmtpPass string ` toml:"smtppass" ` //可选, SMTP授权人密码, 默认时从from中取
SmtpProxy string ` toml:"smtpproxy" ` //可选, SMTP代理地址, 默认时为空
WhiteList [ ] string ` toml:"whitelist" ` //可选,发送白名单,默认为空
BlackList [ ] string ` toml:"blacklist" ` //可选,发送黑名单,默认为空
}
func ( cfg Config ) GetId ( ) string {
return cfg . Id
}
func ( cfg Config ) NewSender ( ) ( Sender , error ) {
return New ( cfg ) , nil
}
type EmailPlainAuthSender struct {
cfg Config
send func ( to string , name , body string ) error
}
func New ( cfg Config ) * EmailPlainAuthSender {
var (
arrFrom = strings . Split ( cfg . From , "/" )
fromName = arrFrom [ 0 ]
fromAddr = arrFrom [ 1 ]
fromPass = arrFrom [ 2 ]
arrSmtp = strings . Split ( cfg . Smtp , ":" )
smtpAddr = arrSmtp [ 0 ]
smtpPort = arrSmtp [ 1 ]
smtpUser = cfg . SmtpUser
smtpPass = cfg . SmtpPass
)
if smtpUser == "" {
smtpUser = fromAddr
}
if smtpPass == "" {
smtpPass = fromPass
}
type emailItem struct {
to string
name string
body string
retry int
}
var whiteListRegs = [ ] * regexp . Regexp { }
for _ , r := range cfg . WhiteList {
whiteListRegs = append ( whiteListRegs , regexp . MustCompile ( r ) )
}
var blackListRegs = [ ] * regexp . Regexp { }
for _ , r := range cfg . BlackList {
blackListRegs = append ( blackListRegs , regexp . MustCompile ( r ) )
}
var addressInWhiteList = func ( address string ) bool {
for _ , reg := range blackListRegs {
if reg . Match ( [ ] byte ( address ) ) {
return false
}
}
if len ( whiteListRegs ) == 0 {
return true
}
for _ , reg := range whiteListRegs {
if reg . Match ( [ ] byte ( address ) ) {
return true
}
}
return false
}
var emailQueue = make ( chan emailItem , 1024 )
var emailSendFunc = func ( to string , name , body string ) ( err error ) {
eml := emailItem { to , name , body , 0 }
emailQueue <- eml
return nil
}
var emailSendFuncInner = func ( ) {
defer func ( ) {
if re := recover ( ) ; re != nil {
log . Errorf ( "email inner sender exit with recover: %v" , re )
}
} ( )
for {
eml , ok := <- emailQueue
if ! ok {
log . Infof ( "emailQueue closed" )
return
}
log . Infof ( "start send email to [%s]" , eml . to )
if ! addressInWhiteList ( eml . to ) {
// white-blck-list
log . Infof ( "send email to [%s] ignored for not in white list." , eml . to )
continue
} else if cfg . DryRun {
// dryrun mode
log . Infof ( "end send email to [%s]: ignored for dryrun mode." , eml . to )
continue
}
// compose the message
m := email . NewHTMLMessage ( eml . name , eml . body )
m . To = [ ] string { eml . to }
m . From = mail . Address { Name : fromName , Address : fromAddr }
// send it to smtp server
auth := smtp . PlainAuth ( "" , smtpUser , smtpPass , smtpAddr )
addr := smtpAddr + ":" + smtpPort
if cfg . SmtpProxy != "" {
addr += "|" + cfg . SmtpProxy
}
if err := email . Send ( addr , auth , m ) ; err != nil {
log . Errorf ( "failed send email to [%s]" , err . Error ( ) )
log . Infof ( "to[%v],from[%s]" , m . To , m . From )
log . Infof ( "smtpUser[%s],smtpPass[%s],smtpAddr[%s:%s],smtpProxy[%s]" ,
smtpUser , secLogPass ( smtpPass ) , smtpAddr , smtpPort , secLogProxy ( cfg . SmtpProxy ) )
if eml . retry < 5 {
go func ( ) {
eml . retry ++
time . Sleep ( time . Duration ( 5 * eml . retry ) * time . Second )
emailQueue <- eml
} ( )
}
continue
}
log . Infof ( "success send email to [%s]" , eml . to )
}
}
go func ( ) {
for {
emailSendFuncInner ( )
log . Infof ( "email inner sender exit abnormal, restart it 5s later..." )
time . Sleep ( 5 * time . Second )
}
} ( )
var sender = & EmailPlainAuthSender {
cfg : cfg ,
send : emailSendFunc ,
}
return sender
}
func ( sender * EmailPlainAuthSender ) Send ( to string , name , body string ) error {
return sender . send ( to , name , body )
}
func ( sender * EmailPlainAuthSender ) SenderType ( ) string {
return "EMAIL" // SENDER_TYPE_EMAIL
}
func ( sender * EmailPlainAuthSender ) SenderSupportAddressType ( ) string {
return "EMAIL_ADDRESS" // SENDER_SUPPORT_ADDRESS_TYPE_EMAIL_ADDRESS
}
func secLogPass ( password string ) string {
n := len ( password )
if n < 3 {
return "*****"
} else if n < 8 {
return "***" + password [ n - 2 : ]
}
return "" + password [ : 1 ] + "**" + password [ n - 2 : ]
}
func secLogProxy ( proxy string ) string {
if strings . HasPrefix ( proxy , "socks5://" ) && strings . Contains ( proxy , "@" ) {
arr := strings . Split ( proxy , "@" )
if len ( arr ) == 2 {
return arr [ 1 ]
}
}
return proxy
}