diff --git a/pkg/models/notifications.go b/pkg/models/notifications.go index 44abf19fcbe..3647fc654d9 100644 --- a/pkg/models/notifications.go +++ b/pkg/models/notifications.go @@ -14,6 +14,7 @@ type SendEmailAttachFile struct { // SendEmailCommand is command for sending emails type SendEmailCommand struct { To []string + SingleEmail bool Template string Subject string Data map[string]interface{} diff --git a/pkg/services/alerting/notifiers/email.go b/pkg/services/alerting/notifiers/email.go index 462b13959a3..775fd7e2bd5 100644 --- a/pkg/services/alerting/notifiers/email.go +++ b/pkg/services/alerting/notifiers/email.go @@ -19,13 +19,25 @@ func init() { Description: "Sends notifications using Grafana server configured SMTP settings", Factory: NewEmailNotifier, OptionsTemplate: ` -

Email addresses

-
- -
-
- You can enter multiple email addresses using a ";" separator -
+

Email settings

+
+ + +
+
+ + +
+
+ You can enter multiple email addresses using a ";" separator +
`, }) } @@ -34,14 +46,16 @@ func init() { // alert notifications over email. type EmailNotifier struct { NotifierBase - Addresses []string - log log.Logger + Addresses []string + SingleEmail bool + log log.Logger } // NewEmailNotifier is the constructor function // for the EmailNotifier. func NewEmailNotifier(model *models.AlertNotification) (alerting.Notifier, error) { addressesString := model.Settings.Get("addresses").MustString() + singleEmail := model.Settings.Get("singleEmail").MustBool(false) if addressesString == "" { return nil, alerting.ValidationError{Reason: "Could not find addresses in settings"} @@ -53,13 +67,14 @@ func NewEmailNotifier(model *models.AlertNotification) (alerting.Notifier, error return &EmailNotifier{ NotifierBase: NewNotifierBase(model), Addresses: addresses, + SingleEmail: singleEmail, log: log.New("alerting.notifier.email"), }, nil } // Notify sends the alert notification. func (en *EmailNotifier) Notify(evalContext *alerting.EvalContext) error { - en.log.Info("Sending alert notification to", "addresses", en.Addresses) + en.log.Info("Sending alert notification to", "addresses", en.Addresses, "singleEmail", en.SingleEmail) ruleURL, err := evalContext.GetRuleURL() if err != nil { @@ -89,6 +104,7 @@ func (en *EmailNotifier) Notify(evalContext *alerting.EvalContext) error { "EvalMatches": evalContext.EvalMatches, }, To: en.Addresses, + SingleEmail: en.SingleEmail, Template: "alert_notification.html", EmbededFiles: []string{}, }, diff --git a/pkg/services/notifications/email.go b/pkg/services/notifications/email.go index aa10a7423c4..82105e8171c 100644 --- a/pkg/services/notifications/email.go +++ b/pkg/services/notifications/email.go @@ -14,6 +14,7 @@ type AttachedFile struct { // Message is representation of the email message type Message struct { To []string + SingleEmail bool From string Subject string Body string diff --git a/pkg/services/notifications/mailer.go b/pkg/services/notifications/mailer.go index 17d0a4c0d57..903294509a4 100644 --- a/pkg/services/notifications/mailer.go +++ b/pkg/services/notifications/mailer.go @@ -12,6 +12,7 @@ import ( "io" "net" "strconv" + "strings" gomail "gopkg.in/mail.v2" @@ -21,16 +22,31 @@ import ( ) func (ns *NotificationService) send(msg *Message) (int, error) { - dialer, err := ns.createDialer() - if err != nil { - return 0, err + messages := []*Message{} + + if msg.SingleEmail { + messages = append(messages, msg) + } else { + for _, address := range msg.To { + copy := *msg + copy.To = []string{address} + messages = append(messages, ©) + } } - var num int - for _, address := range msg.To { + return ns.dialAndSend(messages...) +} + +func (ns *NotificationService) dialAndSend(messages ...*Message) (num int, err error) { + dialer, err := ns.createDialer() + if err != nil { + return + } + + for _, msg := range messages { m := gomail.NewMessage() m.SetHeader("From", msg.From) - m.SetHeader("To", address) + m.SetHeader("To", msg.To...) m.SetHeader("Subject", msg.Subject) ns.setFiles(m, msg) @@ -41,16 +57,15 @@ func (ns *NotificationService) send(msg *Message) (int, error) { m.SetBody("text/html", msg.Body) - e := dialer.DialAndSend(m) - if e != nil { - err = errutil.Wrapf(e, "Failed to send notification to email address: %s", address) + if e := dialer.DialAndSend(m); e != nil { + err = errutil.Wrapf(e, "Failed to send notification to email addresses: %s", strings.Join(msg.To, ";")) continue } num++ } - return num, err + return } // setFiles attaches files in various forms @@ -150,6 +165,7 @@ func (ns *NotificationService) buildEmailMessage(cmd *models.SendEmailCommand) ( return &Message{ To: cmd.To, + SingleEmail: cmd.SingleEmail, From: fmt.Sprintf("%s <%s>", ns.Cfg.Smtp.FromName, ns.Cfg.Smtp.FromAddress), Subject: subject, Body: buffer.String(), diff --git a/pkg/services/notifications/notifications.go b/pkg/services/notifications/notifications.go index 49e1461f2bd..c1836f94fb2 100644 --- a/pkg/services/notifications/notifications.go +++ b/pkg/services/notifications/notifications.go @@ -123,6 +123,7 @@ func (ns *NotificationService) sendEmailCommandHandlerSync(ctx context.Context, Info: cmd.Info, Template: cmd.Template, To: cmd.To, + SingleEmail: cmd.SingleEmail, EmbededFiles: cmd.EmbededFiles, Subject: cmd.Subject, })