email.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. package notifiers
  2. import (
  3. "os"
  4. "strings"
  5. "github.com/grafana/grafana/pkg/bus"
  6. "github.com/grafana/grafana/pkg/infra/log"
  7. "github.com/grafana/grafana/pkg/models"
  8. "github.com/grafana/grafana/pkg/services/alerting"
  9. "github.com/grafana/grafana/pkg/setting"
  10. )
  11. func init() {
  12. alerting.RegisterNotifier(&alerting.NotifierPlugin{
  13. Type: "email",
  14. Name: "Email",
  15. Description: "Sends notifications using Grafana server configured SMTP settings",
  16. Factory: NewEmailNotifier,
  17. OptionsTemplate: `
  18. <h3 class="page-heading">Email addresses</h3>
  19. <div class="gf-form">
  20. <textarea rows="7" class="gf-form-input width-27" required ng-model="ctrl.model.settings.addresses"></textarea>
  21. </div>
  22. <div class="gf-form">
  23. <span>You can enter multiple email addresses using a ";" separator</span>
  24. </div>
  25. `,
  26. })
  27. }
  28. // EmailNotifier is responsible for sending
  29. // alert notifications over email.
  30. type EmailNotifier struct {
  31. NotifierBase
  32. Addresses []string
  33. log log.Logger
  34. }
  35. // NewEmailNotifier is the constructor function
  36. // for the EmailNotifier.
  37. func NewEmailNotifier(model *models.AlertNotification) (alerting.Notifier, error) {
  38. addressesString := model.Settings.Get("addresses").MustString()
  39. if addressesString == "" {
  40. return nil, alerting.ValidationError{Reason: "Could not find addresses in settings"}
  41. }
  42. // split addresses with a few different ways
  43. addresses := strings.FieldsFunc(addressesString, func(r rune) bool {
  44. switch r {
  45. case ',', ';', '\n':
  46. return true
  47. }
  48. return false
  49. })
  50. return &EmailNotifier{
  51. NotifierBase: NewNotifierBase(model),
  52. Addresses: addresses,
  53. log: log.New("alerting.notifier.email"),
  54. }, nil
  55. }
  56. // Notify sends the alert notification.
  57. func (en *EmailNotifier) Notify(evalContext *alerting.EvalContext) error {
  58. en.log.Info("Sending alert notification to", "addresses", en.Addresses)
  59. ruleURL, err := evalContext.GetRuleUrl()
  60. if err != nil {
  61. en.log.Error("Failed get rule link", "error", err)
  62. return err
  63. }
  64. error := ""
  65. if evalContext.Error != nil {
  66. error = evalContext.Error.Error()
  67. }
  68. cmd := &models.SendEmailCommandSync{
  69. SendEmailCommand: models.SendEmailCommand{
  70. Subject: evalContext.GetNotificationTitle(),
  71. Data: map[string]interface{}{
  72. "Title": evalContext.GetNotificationTitle(),
  73. "State": evalContext.Rule.State,
  74. "Name": evalContext.Rule.Name,
  75. "StateModel": evalContext.GetStateModel(),
  76. "Message": evalContext.Rule.Message,
  77. "Error": error,
  78. "RuleUrl": ruleURL,
  79. "ImageLink": "",
  80. "EmbeddedImage": "",
  81. "AlertPageUrl": setting.AppUrl + "alerting",
  82. "EvalMatches": evalContext.EvalMatches,
  83. },
  84. To: en.Addresses,
  85. Template: "alert_notification.html",
  86. EmbededFiles: []string{},
  87. },
  88. }
  89. if evalContext.ImagePublicUrl != "" {
  90. cmd.Data["ImageLink"] = evalContext.ImagePublicUrl
  91. } else {
  92. file, err := os.Stat(evalContext.ImageOnDiskPath)
  93. if err == nil {
  94. cmd.EmbededFiles = []string{evalContext.ImageOnDiskPath}
  95. cmd.Data["EmbeddedImage"] = file.Name()
  96. }
  97. }
  98. err = bus.DispatchCtx(evalContext.Ctx, cmd)
  99. if err != nil {
  100. en.log.Error("Failed to send alert notification email", "error", err)
  101. return err
  102. }
  103. return nil
  104. }