|
|
|
@ -11,12 +11,8 @@ import ( |
|
|
|
|
"fmt" |
|
|
|
|
"html/template" |
|
|
|
|
"net" |
|
|
|
|
"net/mail" |
|
|
|
|
"net/smtp" |
|
|
|
|
"os" |
|
|
|
|
"strconv" |
|
|
|
|
"strings" |
|
|
|
|
"time" |
|
|
|
|
|
|
|
|
|
"github.com/grafana/grafana/pkg/log" |
|
|
|
|
m "github.com/grafana/grafana/pkg/models" |
|
|
|
@ -35,7 +31,7 @@ func processMailQueue() { |
|
|
|
|
for { |
|
|
|
|
select { |
|
|
|
|
case msg := <-mailQueue: |
|
|
|
|
num, err := buildAndSend(msg) |
|
|
|
|
num, err := send(msg) |
|
|
|
|
tos := strings.Join(msg.To, "; ") |
|
|
|
|
info := "" |
|
|
|
|
if err != nil { |
|
|
|
@ -54,130 +50,42 @@ var addToMailQueue = func(msg *Message) { |
|
|
|
|
mailQueue <- msg |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func sendToSmtpServer(recipients []string, msgContent []byte) error { |
|
|
|
|
host, port, err := net.SplitHostPort(setting.Smtp.Host) |
|
|
|
|
func send(msg *Message) (int, error) { |
|
|
|
|
dialer, err := createDialer() |
|
|
|
|
if err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
tlsconfig := &tls.Config{ |
|
|
|
|
InsecureSkipVerify: setting.Smtp.SkipVerify, |
|
|
|
|
ServerName: host, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if setting.Smtp.CertFile != "" { |
|
|
|
|
cert, err := tls.LoadX509KeyPair(setting.Smtp.CertFile, setting.Smtp.KeyFile) |
|
|
|
|
if err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
tlsconfig.Certificates = []tls.Certificate{cert} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
conn, err := net.DialTimeout("tcp", net.JoinHostPort(host, port), time.Second*10) |
|
|
|
|
if err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
defer conn.Close() |
|
|
|
|
|
|
|
|
|
isSecureConn := false |
|
|
|
|
// Start TLS directly if the port ends with 465 (SMTPS protocol)
|
|
|
|
|
if strings.HasSuffix(port, "465") { |
|
|
|
|
conn = tls.Client(conn, tlsconfig) |
|
|
|
|
isSecureConn = true |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
client, err := smtp.NewClient(conn, host) |
|
|
|
|
if err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
hostname, err := os.Hostname() |
|
|
|
|
if err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if err = client.Hello(hostname); err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// If not using SMTPS, alway use STARTTLS if available
|
|
|
|
|
hasStartTLS, _ := client.Extension("STARTTLS") |
|
|
|
|
if !isSecureConn && hasStartTLS { |
|
|
|
|
if err = client.StartTLS(tlsconfig); err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
return 0, err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
canAuth, options := client.Extension("AUTH") |
|
|
|
|
|
|
|
|
|
if canAuth && len(setting.Smtp.User) > 0 { |
|
|
|
|
var auth smtp.Auth |
|
|
|
|
|
|
|
|
|
if strings.Contains(options, "CRAM-MD5") { |
|
|
|
|
auth = smtp.CRAMMD5Auth(setting.Smtp.User, setting.Smtp.Password) |
|
|
|
|
} else if strings.Contains(options, "PLAIN") { |
|
|
|
|
auth = smtp.PlainAuth("", setting.Smtp.User, setting.Smtp.Password, host) |
|
|
|
|
for _, address := range msg.To { |
|
|
|
|
m := gomail.NewMessage() |
|
|
|
|
m.SetHeader("From", msg.From) |
|
|
|
|
m.SetHeader("To", address) |
|
|
|
|
m.SetHeader("Subject", msg.Subject) |
|
|
|
|
for _, file := range msg.EmbededFiles { |
|
|
|
|
m.Embed(file) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if auth != nil { |
|
|
|
|
if err = client.Auth(auth); err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if fromAddress, err := mail.ParseAddress(setting.Smtp.FromAddress); err != nil { |
|
|
|
|
return err |
|
|
|
|
} else { |
|
|
|
|
if err = client.Mail(fromAddress.Address); err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
m.SetBody("text/html", msg.Body) |
|
|
|
|
|
|
|
|
|
for _, rec := range recipients { |
|
|
|
|
if err = client.Rcpt(rec); err != nil { |
|
|
|
|
return err |
|
|
|
|
if err := dialer.DialAndSend(m); err != nil { |
|
|
|
|
return 0, err |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
w, err := client.Data() |
|
|
|
|
if err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
if _, err = w.Write([]byte(msgContent)); err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if err = w.Close(); err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return client.Quit() |
|
|
|
|
return len(msg.To), nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func buildAndSend(msg *Message) (int, error) { |
|
|
|
|
m := gomail.NewMessage() |
|
|
|
|
m.SetHeader("From", msg.From) |
|
|
|
|
m.SetHeader("To", msg.To[0]) |
|
|
|
|
m.SetHeader("Subject", msg.Subject) |
|
|
|
|
for _, file := range msg.EmbededFiles { |
|
|
|
|
m.Embed(file) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
m.SetBody("text/html", msg.Body) |
|
|
|
|
|
|
|
|
|
func createDialer() (*gomail.Dialer, error) { |
|
|
|
|
host, port, err := net.SplitHostPort(setting.Smtp.Host) |
|
|
|
|
|
|
|
|
|
if err != nil { |
|
|
|
|
return 0, err |
|
|
|
|
return nil, err |
|
|
|
|
} |
|
|
|
|
iPort, err := strconv.Atoi(port) |
|
|
|
|
if err != nil { |
|
|
|
|
return 0, err |
|
|
|
|
return nil, err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
d := gomail.NewPlainDialer(host, iPort, setting.Smtp.User, setting.Smtp.Password) |
|
|
|
|
|
|
|
|
|
tlsconfig := &tls.Config{ |
|
|
|
|
InsecureSkipVerify: setting.Smtp.SkipVerify, |
|
|
|
|
ServerName: host, |
|
|
|
@ -186,72 +94,14 @@ func buildAndSend(msg *Message) (int, error) { |
|
|
|
|
if setting.Smtp.CertFile != "" { |
|
|
|
|
cert, err := tls.LoadX509KeyPair(setting.Smtp.CertFile, setting.Smtp.KeyFile) |
|
|
|
|
if err != nil { |
|
|
|
|
return 0, err |
|
|
|
|
return nil, err |
|
|
|
|
} |
|
|
|
|
tlsconfig.Certificates = []tls.Certificate{cert} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
d := gomail.NewPlainDialer(host, iPort, setting.Smtp.User, setting.Smtp.Password) |
|
|
|
|
d.TLSConfig = tlsconfig |
|
|
|
|
if err := d.DialAndSend(m); err != nil { |
|
|
|
|
return 0, err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return 0, nil |
|
|
|
|
/* |
|
|
|
|
m := email.NewHTMLMessage(msg.Subject, msg.Body) |
|
|
|
|
m.From = mail.Address{Name: "From", Address: "alerting@grafana.org"} |
|
|
|
|
m.To = msg.To |
|
|
|
|
|
|
|
|
|
log.Info2("Attaching file", "file", msg.Attachment) |
|
|
|
|
if err := m.Attach(msg.Attachment); err != nil { |
|
|
|
|
return 0, err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// send it
|
|
|
|
|
host, _, _ := net.SplitHostPort(setting.Smtp.Host) |
|
|
|
|
|
|
|
|
|
auth := smtp.PlainAuth("", setting.Smtp.User, setting.Smtp.Password, host) |
|
|
|
|
if err := email.Send(setting.Smtp.Host, auth, m); err != nil { |
|
|
|
|
return 0, err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return 0, nil |
|
|
|
|
|
|
|
|
|
log.Trace("Sending mails to: %s", strings.Join(msg.To, "; ")) |
|
|
|
|
|
|
|
|
|
// get message body
|
|
|
|
|
content := msg.Content() |
|
|
|
|
|
|
|
|
|
if len(msg.To) == 0 { |
|
|
|
|
return 0, fmt.Errorf("empty receive emails") |
|
|
|
|
} else if len(msg.Body) == 0 { |
|
|
|
|
return 0, fmt.Errorf("empty email body") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if msg.Massive { |
|
|
|
|
// send mail to multiple emails one by one
|
|
|
|
|
num := 0 |
|
|
|
|
for _, to := range msg.To { |
|
|
|
|
body := []byte("To: " + to + "\r\n" + content) |
|
|
|
|
err := sendToSmtpServer([]string{to}, body) |
|
|
|
|
if err != nil { |
|
|
|
|
return num, err |
|
|
|
|
} |
|
|
|
|
num++ |
|
|
|
|
} |
|
|
|
|
return num, nil |
|
|
|
|
} else { |
|
|
|
|
body := []byte("To: " + strings.Join(msg.To, ";") + "\r\n" + content) |
|
|
|
|
|
|
|
|
|
// send to multiple emails in one message
|
|
|
|
|
err := sendToSmtpServer(msg.To, body) |
|
|
|
|
if err != nil { |
|
|
|
|
return 0, err |
|
|
|
|
} else { |
|
|
|
|
return 1, nil |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
*/ |
|
|
|
|
return d, nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func buildEmailMessage(cmd *m.SendEmailCommand) (*Message, error) { |
|
|
|
|