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,
})