Rewrite of SendMail function
The SendMail function is rewritten and has the following new functionality: - It is optional to skip verification of keys. The config option SKIP_VERIFY is added - If the port is 465, or ending on 465, the TLS(/SSL) connection is started first.
This commit is contained in:
parent
0a697517ac
commit
87be137b88
3 changed files with 49 additions and 19 deletions
|
@ -94,7 +94,10 @@ SUBJECT = %(APP_NAME)s
|
||||||
; Mail server
|
; Mail server
|
||||||
; Gmail: smtp.gmail.com:587
|
; Gmail: smtp.gmail.com:587
|
||||||
; QQ: smtp.qq.com:25
|
; QQ: smtp.qq.com:25
|
||||||
|
; Note, if the port ends with "465", SMTPS will be used. Using STARTTLS on port 587 is recommended per RFC 6409. If the server supports STARTTLS it will always be used.
|
||||||
HOST =
|
HOST =
|
||||||
|
; Do not verify the certificate of the server. Only use this for self-signed certificates
|
||||||
|
SKIP_VERIFY =
|
||||||
; Mail from address
|
; Mail from address
|
||||||
FROM =
|
FROM =
|
||||||
; Mailer user name and password
|
; Mailer user name and password
|
||||||
|
|
|
@ -67,22 +67,53 @@ func processMailQueue() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// sendMail allows mail with self-signed certificates.
|
// sendMail allows mail with self-signed certificates.
|
||||||
func sendMail(hostAddressWithPort string, auth smtp.Auth, from string, recipients []string, msgContent []byte) error {
|
func sendMail(settings *setting.Mailer, from string, recipients []string, msgContent []byte) error {
|
||||||
client, err := smtp.Dial(hostAddressWithPort)
|
host, port, err := net.SplitHostPort(settings.Host)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
host, _, _ := net.SplitHostPort(hostAddressWithPort)
|
if len(port) == 0 {
|
||||||
tlsConn := &tls.Config{
|
port = "587"
|
||||||
InsecureSkipVerify: true,
|
}
|
||||||
|
|
||||||
|
tlsconfig := &tls.Config{
|
||||||
|
InsecureSkipVerify: settings.SkipVerify,
|
||||||
ServerName: host,
|
ServerName: host,
|
||||||
}
|
}
|
||||||
if err = client.StartTLS(tlsConn); err != nil {
|
|
||||||
|
var conn net.Conn
|
||||||
|
if conn, err = net.Dial("tcp", net.JoinHostPort(host, port)); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
connection_secure := false
|
||||||
|
// Start TLS directly if the port ends with 465 (SMTPS protocol)
|
||||||
|
if strings.HasSuffix(port, "465") {
|
||||||
|
conn = tls.Client(conn, tlsconfig)
|
||||||
|
connection_secure = true
|
||||||
|
}
|
||||||
|
|
||||||
|
var client *smtp.Client
|
||||||
|
if client, err = smtp.NewClient(conn, host); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if ok, _ := client.Extension("AUTH"); ok && auth != nil {
|
// If not using SMTPS, alway use STARTTLS if available
|
||||||
|
has_starttls, _ := client.Extension("STARTTLS")
|
||||||
|
if !connection_secure && has_starttls {
|
||||||
|
if err = client.StartTLS(tlsconfig); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auth_available, _ := client.Extension("AUTH")
|
||||||
|
|
||||||
|
// Possible improvement: only plain authentication is now available.
|
||||||
|
// Maybe in future CRAM MD5 as well?
|
||||||
|
if auth_available && len(settings.User) > 0 {
|
||||||
|
auth := smtp.PlainAuth("", settings.User, settings.Passwd, host)
|
||||||
if err = client.Auth(auth); err != nil {
|
if err = client.Auth(auth); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -116,7 +147,6 @@ func sendMail(hostAddressWithPort string, auth smtp.Auth, from string, recipient
|
||||||
// Direct Send mail message
|
// Direct Send mail message
|
||||||
func Send(msg *Message) (int, error) {
|
func Send(msg *Message) (int, error) {
|
||||||
log.Trace("Sending mails to: %s", strings.Join(msg.To, "; "))
|
log.Trace("Sending mails to: %s", strings.Join(msg.To, "; "))
|
||||||
host := strings.Split(setting.MailService.Host, ":")
|
|
||||||
|
|
||||||
// get message body
|
// get message body
|
||||||
content := msg.Content()
|
content := msg.Content()
|
||||||
|
@ -127,17 +157,12 @@ func Send(msg *Message) (int, error) {
|
||||||
return 0, fmt.Errorf("empty email body")
|
return 0, fmt.Errorf("empty email body")
|
||||||
}
|
}
|
||||||
|
|
||||||
var auth smtp.Auth
|
|
||||||
if len(setting.MailService.Passwd) > 0 {
|
|
||||||
auth = smtp.PlainAuth("", setting.MailService.User, setting.MailService.Passwd, host[0])
|
|
||||||
}
|
|
||||||
|
|
||||||
if msg.Massive {
|
if msg.Massive {
|
||||||
// send mail to multiple emails one by one
|
// send mail to multiple emails one by one
|
||||||
num := 0
|
num := 0
|
||||||
for _, to := range msg.To {
|
for _, to := range msg.To {
|
||||||
body := []byte("To: " + to + "\r\n" + content)
|
body := []byte("To: " + to + "\r\n" + content)
|
||||||
err := sendMail(setting.MailService.Host, auth, msg.From, []string{to}, body)
|
err := sendMail(setting.MailService, msg.From, []string{to}, body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return num, err
|
return num, err
|
||||||
}
|
}
|
||||||
|
@ -148,7 +173,7 @@ func Send(msg *Message) (int, error) {
|
||||||
body := []byte("To: " + strings.Join(msg.To, ";") + "\r\n" + content)
|
body := []byte("To: " + strings.Join(msg.To, ";") + "\r\n" + content)
|
||||||
|
|
||||||
// send to multiple emails in one message
|
// send to multiple emails in one message
|
||||||
err := sendMail(setting.MailService.Host, auth, msg.From, msg.To, body)
|
err := sendMail(setting.MailService, msg.From, msg.To, body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -437,6 +437,7 @@ type Mailer struct {
|
||||||
Host string
|
Host string
|
||||||
From string
|
From string
|
||||||
User, Passwd string
|
User, Passwd string
|
||||||
|
SkipVerify bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type OauthInfo struct {
|
type OauthInfo struct {
|
||||||
|
@ -463,10 +464,11 @@ func newMailService() {
|
||||||
}
|
}
|
||||||
|
|
||||||
MailService = &Mailer{
|
MailService = &Mailer{
|
||||||
Name: Cfg.MustValue("mailer", "NAME", AppName),
|
Name: Cfg.MustValue("mailer", "NAME", AppName),
|
||||||
Host: Cfg.MustValue("mailer", "HOST"),
|
Host: Cfg.MustValue("mailer", "HOST"),
|
||||||
User: Cfg.MustValue("mailer", "USER"),
|
User: Cfg.MustValue("mailer", "USER"),
|
||||||
Passwd: Cfg.MustValue("mailer", "PASSWD"),
|
Passwd: Cfg.MustValue("mailer", "PASSWD"),
|
||||||
|
SkipVerify: Cfg.MustBool("mailer", "SKIP_VERIFY", false),
|
||||||
}
|
}
|
||||||
MailService.From = Cfg.MustValue("mailer", "FROM", MailService.User)
|
MailService.From = Cfg.MustValue("mailer", "FROM", MailService.User)
|
||||||
log.Info("Mail Service Enabled")
|
log.Info("Mail Service Enabled")
|
||||||
|
|
Reference in a new issue