diff --git a/emails/templates/ng_alert_notification.html b/emails/templates/ng_alert_notification.html
new file mode 100644
index 00000000000..71d0542640a
--- /dev/null
+++ b/emails/templates/ng_alert_notification.html
@@ -0,0 +1,130 @@
+[[Subject .Subject "[[.Title]]"]]
+
+
+
+
+
+
+
+
+
+
+ [[ if gt (len .Alerts.Firing) 0 ]]
+
+ [[ else ]]
+ |
+ [[ end ]].
+ [[ .Alerts | len ]] alert[[ if gt (len .Alerts) 1 ]]s[[ end ]] for
+ [[ range .GroupLabels.SortedPairs ]]
+ [[ .Name ]]=[[ .Value ]]
+ [[ end ]]
+ |
+
+
+
+
+ [[ if gt (len .Alerts.Firing) 0 ]]
+
+
+ ([[ .Alerts.Firing | len ]]) Firing
+ |
+
+ [[ end ]]
+ [[ range .Alerts.Firing ]]
+
+
+ Labels
+ [[ range .Labels.SortedPairs ]][[ .Name ]] = [[ .Value ]] [[ end ]]
+ [[ if gt (len .Annotations) 0 ]]Annotations [[ end ]]
+ [[ range .Annotations.SortedPairs ]][[ .Name ]] = [[ .Value ]] [[ end ]]
+ Source
+ |
+
+ [[ end ]]
+
+ [[ if gt (len .Alerts.Resolved) 0 ]]
+ [[ if gt (len .Alerts.Firing) 0 ]]
+
+
+
+
+
+ |
+
+ [[ end ]]
+
+
+ ([[ .Alerts.Resolved | len ]]) Resolved
+ |
+
+ [[ end ]]
+ [[ range .Alerts.Resolved ]]
+
+
+ Labels
+ [[ range .Labels.SortedPairs ]][[ .Name ]] = [[ .Value ]] [[ end ]]
+ [[ if gt (len .Annotations) 0 ]]Annotations [[ end ]]
+ [[ range .Annotations.SortedPairs ]][[ .Name ]] = [[ .Value ]] [[ end ]]
+ Source
+ |
+
+ [[ end ]]
+
+ |
+
+
+ |
+
+
+
+
+
+
+
+
diff --git a/go.sum b/go.sum
index fc6fdafa73e..90912aaf986 100644
--- a/go.sum
+++ b/go.sum
@@ -30,6 +30,7 @@ cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUM
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
cloud.google.com/go/bigtable v1.1.0/go.mod h1:B6ByKcIdYmhoyDzmOnQxyOhN6r05qnewYIxxG6L0/b4=
+cloud.google.com/go/bigtable v1.2.0 h1:F4cCmA4nuV84V5zYQ3MKY+M1Cw1avHDuf3S/LcZPA9c=
cloud.google.com/go/bigtable v1.2.0/go.mod h1:JcVAOl45lrTmQfLj7T6TxyMzIN/3FGGcFm+2xVAli2o=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
@@ -183,7 +184,6 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY
github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A=
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
-github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496 h1:zV3ejI06GQ59hwDQAvmK1qxOQGB3WuVTRoY0okPTAv0=
github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg=
github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535/go.mod h1:oGkLhpf+kjZl6xBf758TQhh5XrAeiJv/7FRz/2spLIg=
github.com/asaskevich/govalidator v0.0.0-20200907205600-7a23bdc65eef h1:46PFijGLmAjMPwCCCo7Jf0W6f9slllCkkv7vyc1yOSg=
@@ -233,14 +233,12 @@ github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b h1:L/QXpzIa3pO
github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b/go.mod h1:H0wQNHz2YrLsuXOZozoeDmnHXkNCRmMW0gwFWDfEZDA=
github.com/bsm/sarama-cluster v2.1.13+incompatible/go.mod h1:r7ao+4tTNXvWm+VRpRJchr2kQhqxgmAp2iEX5W96gMM=
github.com/c-bata/go-prompt v0.2.2/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34=
-github.com/c2h5oh/datasize v0.0.0-20200112174442-28bbd4740fee h1:BnPxIde0gjtTnc9Er7cxvBk8DHLWhEux0SxayC8dP6I=
github.com/c2h5oh/datasize v0.0.0-20200112174442-28bbd4740fee/go.mod h1:S/7n9copUssQ56c7aAgHqftWO4LTf4xY6CGWt8Bc+3M=
github.com/casbin/casbin/v2 v2.1.2/go.mod h1:YcPU1XXisHhLzuxH9coDNf2FbKpjGlbCg3n9yuLkIJQ=
github.com/cenkalti/backoff v0.0.0-20181003080854-62661b46c409/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/cenkalti/backoff v1.0.0/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
-github.com/cenkalti/backoff/v4 v4.0.2 h1:JIufpQLbh4DkbQoii76ItQIUFzevQSqOLZca4eamEDs=
github.com/cenkalti/backoff/v4 v4.0.2/go.mod h1:eEew/i+1Q6OrCDZh3WiXYv3+nJwBASZ8Bog/87DQnVg=
github.com/cenkalti/backoff/v4 v4.1.0 h1:c8LkOFQTzuO0WBM/ae5HdGQuZPfPxp7lqBRwQRm4fSc=
github.com/cenkalti/backoff/v4 v4.1.0/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
@@ -482,7 +480,6 @@ github.com/go-openapi/analysis v0.18.0/go.mod h1:IowGgpVeD0vNm45So8nr+IcQ3pxVtpR
github.com/go-openapi/analysis v0.19.2/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk=
github.com/go-openapi/analysis v0.19.4/go.mod h1:3P1osvZa9jKjb8ed2TPng3f0i/UY9snX6gxi44djMjk=
github.com/go-openapi/analysis v0.19.5/go.mod h1:hkEAkxagaIvIP7VTn8ygJNkd4kAYON2rCu0v0ObL0AU=
-github.com/go-openapi/analysis v0.19.10 h1:5BHISBAXOc/aJK25irLZnx2D3s6WyYaY9D4gmuz9fdE=
github.com/go-openapi/analysis v0.19.10/go.mod h1:qmhS3VNFxBlquFJ0RGoDtylO9y4pgTAUNE9AEEMdlJQ=
github.com/go-openapi/analysis v0.19.16/go.mod h1:GLInF007N83Ad3m8a/CbQ5TPzdnGT7workfHwuVjNVk=
github.com/go-openapi/analysis v0.20.0 h1:UN09o0kNhleunxW7LR+KnltD0YrJ8FF03pSqvAN3Vro=
@@ -492,12 +489,10 @@ github.com/go-openapi/errors v0.17.2/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQH
github.com/go-openapi/errors v0.18.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
github.com/go-openapi/errors v0.19.2/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94=
github.com/go-openapi/errors v0.19.3/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94=
-github.com/go-openapi/errors v0.19.4 h1:fSGwO1tSYHFu70NKaWJt5Qh0qoBRtCm/mXS1yhf+0W0=
github.com/go-openapi/errors v0.19.4/go.mod h1:qX0BLWsyaKfvhluLejVpVNwNRdXZhEbTA4kxxpKBC94=
github.com/go-openapi/errors v0.19.6/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M=
github.com/go-openapi/errors v0.19.7/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M=
github.com/go-openapi/errors v0.19.8/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M=
-github.com/go-openapi/errors v0.19.9 h1:9SnKdGhiPZHF3ttwFMiCBEb8jQ4IDdrK+5+a0oTygA4=
github.com/go-openapi/errors v0.19.9/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M=
github.com/go-openapi/errors v0.20.0 h1:Sxpo9PjEHDzhs3FbnGNonvDgWcMW2U7wGTcDDSFSceM=
github.com/go-openapi/errors v0.20.0/go.mod h1:cM//ZKUKyO06HSwqAelJ5NsEMMcpa6VpXe8DOa1Mi1M=
@@ -524,7 +519,6 @@ github.com/go-openapi/loads v0.19.0/go.mod h1:72tmFy5wsWx89uEVddd0RjRWPZm92WRLhf
github.com/go-openapi/loads v0.19.2/go.mod h1:QAskZPMX5V0C2gvfkGZzJlINuP7Hx/4+ix5jWFxsNPs=
github.com/go-openapi/loads v0.19.3/go.mod h1:YVfqhUCdahYwR3f3iiwQLhicVRvLlU/WO5WPaZvcvSI=
github.com/go-openapi/loads v0.19.4/go.mod h1:zZVHonKd8DXyxyw4yfnVjPzBjIQcLt0CCsn0N0ZrQsk=
-github.com/go-openapi/loads v0.19.5 h1:jZVYWawIQiA1NBnHla28ktg6hrcfTHsCE+3QLVRBIls=
github.com/go-openapi/loads v0.19.5/go.mod h1:dswLCAdonkRufe/gSUC3gN8nTSaB9uaS2es0x5/IbjY=
github.com/go-openapi/loads v0.19.6/go.mod h1:brCsvE6j8mnbmGBh103PT/QLHfbyDxA4hsKvYBNEGVc=
github.com/go-openapi/loads v0.19.7/go.mod h1:brCsvE6j8mnbmGBh103PT/QLHfbyDxA4hsKvYBNEGVc=
@@ -536,10 +530,8 @@ github.com/go-openapi/runtime v0.18.0/go.mod h1:uI6pHuxWYTy94zZxgcwJkUWa9wbIlhte
github.com/go-openapi/runtime v0.19.0/go.mod h1:OwNfisksmmaZse4+gpV3Ne9AyMOlP1lt4sK4FXt0O64=
github.com/go-openapi/runtime v0.19.3/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4=
github.com/go-openapi/runtime v0.19.4/go.mod h1:X277bwSUBxVlCYR3r7xgZZGKVvBd/29gLDlFGtJ8NL4=
-github.com/go-openapi/runtime v0.19.15 h1:2GIefxs9Rx1vCDNghRtypRq+ig8KSLrjHbAYI/gCLCM=
github.com/go-openapi/runtime v0.19.15/go.mod h1:dhGWCTKRXlAfGnQG0ONViOZpjfg0m2gUt9nTQPQZuoo=
github.com/go-openapi/runtime v0.19.16/go.mod h1:5P9104EJgYcizotuXhEuUrzVc+j1RiSjahULvYmlv98=
-github.com/go-openapi/runtime v0.19.24 h1:TqagMVlRAOTwllE/7hNKx6rQ10O6T8ZzeJdMjSTKaD4=
github.com/go-openapi/runtime v0.19.24/go.mod h1:Lm9YGCeecBnUUkFTxPC4s1+lwrkJ0pthx8YvyjCfkgk=
github.com/go-openapi/runtime v0.19.26 h1:K/6PoVNj5WJXUnMk+VEbELeXjtBkCS1UxTDa04tdXE0=
github.com/go-openapi/runtime v0.19.26/go.mod h1:BvrQtn6iVb2QmiVXRsFAm6ZCAZBpbVKFfN6QWCp582M=
@@ -1457,7 +1449,6 @@ github.com/sanity-io/litter v1.2.0/go.mod h1:JF6pZUFgu2Q0sBZ+HSV35P8TVPI1TTzEwyu
github.com/santhosh-tekuri/jsonschema v1.2.4/go.mod h1:TEAUOeZSmIxTTuHatJzrvARHiuO9LYd+cIxzgEHCQI4=
github.com/satori/go.uuid v0.0.0-20160603004225-b111a074d5ef/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
-github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b h1:gQZ0qzfKHQIybLANtM3mBXNUtOfsCFXeTsnBqCsx1KM=
github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/schollz/closestmatch v2.1.0+incompatible/go.mod h1:RtP1ddjLong6gTkbtmuhtR2uUrrJOpYzYRvbcPAid+g=
github.com/schollz/progressbar/v3 v3.3.4/go.mod h1:Rp5lZwpgtYmlvmGo1FyDwXMqagyRBQYSDwzlP9QDu84=
@@ -1839,7 +1830,6 @@ golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwY
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
-golang.org/x/net v0.0.0-20210119194325-5f4716e94777 h1:003p0dJM77cxMSyCPFphvZf/Y5/NXf5fzg6ufd1/Oew=
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110 h1:qWPm9rbaAMKs8Bq/9LRpbMqxWRVUAQwMI9fVrssnTfw=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
diff --git a/pkg/services/ngalert/notifier/channels/email.go b/pkg/services/ngalert/notifier/channels/email.go
new file mode 100644
index 00000000000..b2cf32e821b
--- /dev/null
+++ b/pkg/services/ngalert/notifier/channels/email.go
@@ -0,0 +1,92 @@
+package channels
+
+import (
+ "context"
+ "net/url"
+
+ gokit_log "github.com/go-kit/kit/log"
+ "github.com/grafana/grafana/pkg/infra/log"
+ "github.com/grafana/grafana/pkg/models"
+ "github.com/grafana/grafana/pkg/services/alerting"
+ old_notifiers "github.com/grafana/grafana/pkg/services/alerting/notifiers"
+ "github.com/grafana/grafana/pkg/util"
+
+ "github.com/grafana/grafana/pkg/bus"
+ "github.com/prometheus/alertmanager/notify"
+ "github.com/prometheus/alertmanager/template"
+ "github.com/prometheus/alertmanager/types"
+ "github.com/prometheus/common/model"
+)
+
+// EmailNotifier is responsible for sending
+// alert notifications over email.
+type EmailNotifier struct {
+ old_notifiers.NotifierBase
+ Addresses []string
+ SingleEmail bool
+ log log.Logger
+ externalUrl *url.URL
+}
+
+// NewEmailNotifier is the constructor function
+// for the EmailNotifier.
+func NewEmailNotifier(model *models.AlertNotification) (*EmailNotifier, 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"}
+ }
+
+ // split addresses with a few different ways
+ addresses := util.SplitEmails(addressesString)
+
+ // TODO: remove this URL hack and add an actual external URL.
+ u, err := url.Parse("http://localhost")
+ if err != nil {
+ return nil, err
+ }
+
+ return &EmailNotifier{
+ NotifierBase: old_notifiers.NewNotifierBase(model),
+ Addresses: addresses,
+ SingleEmail: singleEmail,
+ log: log.New("alerting.notifier.email"),
+ externalUrl: u,
+ }, nil
+}
+
+// Notify sends the alert notification.
+func (en *EmailNotifier) Notify(ctx context.Context, as ...*types.Alert) error {
+ // TODO(codesome): make sure the receiver name is added in the ctx before calling this.
+ ctx = notify.WithReceiverName(ctx, "email-notification-channel") // Dummy.
+ // TODO(codesome): make sure the group labels is added in the ctx before calling this.
+ ctx = notify.WithGroupLabels(ctx, model.LabelSet{}) // Dummy.
+
+ // We only need ExternalURL from this template object. This hack should go away with https://github.com/prometheus/alertmanager/pull/2508.
+ data := notify.GetTemplateData(ctx, &template.Template{ExternalURL: en.externalUrl}, as, gokit_log.NewNopLogger())
+
+ cmd := &models.SendEmailCommandSync{
+ SendEmailCommand: models.SendEmailCommand{
+ Subject: "TODO",
+ Data: map[string]interface{}{
+ "Title": "TODO",
+ "Subject": "TODO",
+ "Receiver": data.Receiver,
+ "Status": data.Status,
+ "Alerts": data.Alerts,
+ "GroupLabels": data.GroupLabels,
+ "CommonLabels": data.CommonLabels,
+ "CommonAnnotations": data.CommonAnnotations,
+ "ExternalURL": data.ExternalURL,
+ "RuleUrl": "TODO",
+ "AlertPageUrl": "TODO",
+ },
+ To: en.Addresses,
+ SingleEmail: en.SingleEmail,
+ Template: "ng_alert_notification.html",
+ },
+ }
+
+ return bus.DispatchCtx(ctx, cmd)
+}
diff --git a/pkg/services/ngalert/notifier/channels/email_test.go b/pkg/services/ngalert/notifier/channels/email_test.go
new file mode 100644
index 00000000000..47f154fc6fe
--- /dev/null
+++ b/pkg/services/ngalert/notifier/channels/email_test.go
@@ -0,0 +1,59 @@
+package channels
+
+import (
+ "testing"
+
+ "github.com/grafana/grafana/pkg/components/simplejson"
+ "github.com/grafana/grafana/pkg/models"
+ "github.com/stretchr/testify/require"
+)
+
+func TestEmailNotifier(t *testing.T) {
+ t.Run("empty settings should return error", func(t *testing.T) {
+ json := `{ }`
+
+ settingsJSON, _ := simplejson.NewJson([]byte(json))
+ model := &models.AlertNotification{
+ Name: "ops",
+ Type: "email",
+ Settings: settingsJSON,
+ }
+
+ _, err := NewEmailNotifier(model)
+ require.Error(t, err)
+ })
+
+ t.Run("from settings", func(t *testing.T) {
+ json := `{"addresses": "ops@grafana.org"}`
+ settingsJSON, err := simplejson.NewJson([]byte(json))
+ require.NoError(t, err)
+
+ emailNotifier, err := NewEmailNotifier(&models.AlertNotification{
+ Name: "ops",
+ Type: "email",
+ Settings: settingsJSON,
+ })
+
+ require.NoError(t, err)
+ require.Equal(t, "ops", emailNotifier.Name)
+ require.Equal(t, "email", emailNotifier.Type)
+ require.Equal(t, []string{"ops@grafana.org"}, emailNotifier.Addresses)
+ })
+
+ t.Run("from settings with two emails", func(t *testing.T) {
+ json := `{"addresses": "ops@grafana.org;dev@grafana.org"}`
+ settingsJSON, err := simplejson.NewJson([]byte(json))
+ require.NoError(t, err)
+
+ emailNotifier, err := NewEmailNotifier(&models.AlertNotification{
+ Name: "ops",
+ Type: "email",
+ Settings: settingsJSON,
+ })
+
+ require.NoError(t, err)
+ require.Equal(t, "ops", emailNotifier.Name)
+ require.Equal(t, "email", emailNotifier.Type)
+ require.Equal(t, []string{"ops@grafana.org", "dev@grafana.org"}, emailNotifier.Addresses)
+ })
+}
diff --git a/pkg/services/notifications/mailer.go b/pkg/services/notifications/mailer.go
index 92c8eb6c904..c44b0df2383 100644
--- a/pkg/services/notifications/mailer.go
+++ b/pkg/services/notifications/mailer.go
@@ -22,7 +22,7 @@ import (
"github.com/grafana/grafana/pkg/util/errutil"
)
-func (ns *NotificationService) send(msg *Message) (int, error) {
+func (ns *NotificationService) Send(msg *Message) (int, error) {
messages := []*Message{}
if msg.SingleEmail {
diff --git a/pkg/services/notifications/notifications.go b/pkg/services/notifications/notifications.go
index a6d709ac338..797424c5e4d 100644
--- a/pkg/services/notifications/notifications.go
+++ b/pkg/services/notifications/notifications.go
@@ -83,7 +83,7 @@ func (ns *NotificationService) Run(ctx context.Context) error {
ns.log.Error("Failed to send webrequest ", "error", err)
}
case msg := <-ns.mailQueue:
- num, err := ns.send(msg)
+ num, err := ns.Send(msg)
tos := strings.Join(msg.To, "; ")
info := ""
if err != nil {
@@ -133,7 +133,7 @@ func (ns *NotificationService) sendEmailCommandHandlerSync(ctx context.Context,
return err
}
- _, err = ns.send(message)
+ _, err = ns.Send(message)
return err
}