email.go 3.2 KB

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