mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Alerting: Adds support for sending a single email to all recipients in notification channel (#21091)
When an alert is sent by e-mail, the process sends an e-mail to each recipient separately. This PR is a single delivery to all recipients. For companies that use e-mail extensively, this is necessary in order not to overload the sending queue. Replaces #18013 Fixes #12650 Co-authored-by: Henrique Oliveira <holiiveira@users.noreply.github.com>
This commit is contained in:
parent
8a02fa7691
commit
0f0772b629
@ -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{}
|
||||
|
@ -19,13 +19,25 @@ func init() {
|
||||
Description: "Sends notifications using Grafana server configured SMTP settings",
|
||||
Factory: NewEmailNotifier,
|
||||
OptionsTemplate: `
|
||||
<h3 class="page-heading">Email addresses</h3>
|
||||
<div class="gf-form">
|
||||
<textarea rows="7" class="gf-form-input width-27" required ng-model="ctrl.model.settings.addresses"></textarea>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<span>You can enter multiple email addresses using a ";" separator</span>
|
||||
</div>
|
||||
<h3 class="page-heading">Email settings</h3>
|
||||
<div class="gf-form">
|
||||
<gf-form-switch
|
||||
class="gf-form"
|
||||
label="Single email"
|
||||
label-class="width-8"
|
||||
checked="ctrl.model.settings.singleEmail"
|
||||
tooltip="Send a single email to all recipients">
|
||||
</gf-form-switch>
|
||||
</div>
|
||||
<div class="gf-form">
|
||||
<label class="gf-form-label width-8">
|
||||
Addresses
|
||||
</label>
|
||||
<textarea rows="7" class="gf-form-input width-27" required ng-model="ctrl.model.settings.addresses"></textarea>
|
||||
</div>
|
||||
<div class="gf-form offset-width-8">
|
||||
<span>You can enter multiple email addresses using a ";" separator</span>
|
||||
</div>
|
||||
`,
|
||||
})
|
||||
}
|
||||
@ -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{},
|
||||
},
|
||||
|
@ -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
|
||||
|
@ -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(),
|
||||
|
@ -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,
|
||||
})
|
||||
|
Loading…
Reference in New Issue
Block a user