diff --git a/pkg/models/notifications.go b/pkg/models/notifications.go index 5be5f6438ae..80803b3be08 100644 --- a/pkg/models/notifications.go +++ b/pkg/models/notifications.go @@ -8,7 +8,6 @@ type SendEmailCommand struct { To []string Template string Data map[string]interface{} - Massive bool Info string EmbededFiles []string } diff --git a/pkg/services/notifications/email.go b/pkg/services/notifications/email.go index 792acdbaca3..803f2096b56 100644 --- a/pkg/services/notifications/email.go +++ b/pkg/services/notifications/email.go @@ -10,18 +10,10 @@ type Message struct { From string Subject string Body string - Massive bool Info string EmbededFiles []string } -// create mail content -func (m *Message) Content() string { - contentType := "text/html; charset=UTF-8" - content := "From: " + m.From + "\r\nSubject: " + m.Subject + "\r\nContent-Type: " + contentType + "\r\n\r\n" + m.Body - return content -} - func setDefaultTemplateData(data map[string]interface{}, u *m.User) { data["AppUrl"] = setting.AppUrl data["BuildVersion"] = setting.BuildVersion diff --git a/pkg/services/notifications/mailer.go b/pkg/services/notifications/mailer.go index 2d58a1e5c71..9e54e906d99 100644 --- a/pkg/services/notifications/mailer.go +++ b/pkg/services/notifications/mailer.go @@ -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) { diff --git a/pkg/services/notifications/notifications.go b/pkg/services/notifications/notifications.go index db36e4e96fb..8a13eec2dc8 100644 --- a/pkg/services/notifications/notifications.go +++ b/pkg/services/notifications/notifications.go @@ -90,7 +90,6 @@ func sendEmailCommandHandlerSync(ctx context.Context, cmd *m.SendEmailCommandSyn message, err := buildEmailMessage(&m.SendEmailCommand{ Data: cmd.Data, Info: cmd.Info, - Massive: cmd.Massive, Template: cmd.Template, To: cmd.To, EmbededFiles: cmd.EmbededFiles, @@ -100,7 +99,7 @@ func sendEmailCommandHandlerSync(ctx context.Context, cmd *m.SendEmailCommandSyn return err } - _, err = buildAndSend(message) + _, err = send(message) return err }