M README.md => README.md +8 -3
@@ 16,9 16,9 @@ You can specify the configuration file location with the `--config` flag. By def
the configuration file will be read from `/etc/ntfy-alertmanager/config`. The format
of this file is [scfg].
-ntfy-alertmanager has support for setting ntfy [priority], [tags], [icon] and [action buttons]
-(which can be used to create an Alertmanager silence).
-Define a decreasing order of labels in the config file and map those labels to tags, priority or an icon.
+ntfy-alertmanager has support for setting ntfy [priority], [tags], [icon], [action buttons]
+(which can be used to create an Alertmanager silence) and [email notifications].
+Define a decreasing order of labels in the config file and map those labels to tags, priority, an icon or an email address.
- For priority and icon the first found value will be chosen. An icon for "resolved" alerts will take precedence.
- Tags are added together.
@@ 47,6 47,8 @@ labels {
priority 5
tags "rotating_light"
icon "https://foo.com/critical.png"
+ # Forward messages which severity "critical" to the specified email address.
+ email-address foo@bar.com
}
severity "info" {
@@ 73,6 75,8 @@ ntfy {
# ntfy authentication via access tokens (https://docs.ntfy.sh/publish/#access-tokens)
# Either access-token or a user/password combination can be used - not both.
access-token foobar
+ # Forward all messages to the specified email address.
+ email-address foo@bar.com
}
alertmanager {
@@ 135,6 139,7 @@ or write to me directly on matrix [@xenrox:xenrox.net].
[tags]: https://ntfy.sh/docs/publish/#tags-emojis
[icon]: https://docs.ntfy.sh/publish/#icons
[action buttons]: https://docs.ntfy.sh/publish/#action-buttons
+[email notifications]: https://docs.ntfy.sh/publish/#e-mail-notifications
[issue tracker]: https://todo.xenrox.net/~xenrox/ntfy-alertmanager
[mailing list]: https://lists.xenrox.net/~xenrox/public-inbox
[@xenrox:xenrox.net]: https://matrix.to/#/@xenrox:xenrox.net
M config.go => config.go +23 -7
@@ 38,10 38,11 @@ type config struct {
}
type ntfyConfig struct {
- Topic string
- User string
- Password string
- AccessToken string
+ Topic string
+ User string
+ Password string
+ AccessToken string
+ emailAddress string
}
type labels struct {
@@ 50,9 51,10 @@ type labels struct {
}
type labelConfig struct {
- Priority string
- Tags []string
- Icon string
+ Priority string
+ Tags []string
+ Icon string
+ emailAddress string
}
type cacheConfig struct {
@@ 201,6 203,13 @@ func readConfig(path string) (*config, error) {
}
}
+ d = labelDir.Children.Get("email-address")
+ if d != nil {
+ if err := d.ParseParams(&labelConfig.emailAddress); err != nil {
+ return nil, err
+ }
+ }
+
labels[fmt.Sprintf("%s:%s", labelName, name)] = *labelConfig
}
}
@@ 251,6 260,13 @@ func readConfig(path string) (*config, error) {
return nil, errors.New("ntfy: cannot use both an access-token and a user/password at the same time")
}
+ d = ntfyDir.Children.Get("email-address")
+ if d != nil {
+ if err := d.ParseParams(&config.ntfy.emailAddress); err != nil {
+ return nil, err
+ }
+ }
+
cacheDir := cfg.Get("cache")
if cacheDir != nil {
M config_test.go => config_test.go +7 -1
@@ 24,6 24,7 @@ labels {
priority 5
tags "rotating_light"
icon "https://foo.com/critical.png"
+ email-address foo@bar.com
}
severity "info" {
@@ 70,7 71,12 @@ cache {
ntfy: ntfyConfig{Topic: "https://ntfy.sh/alertmanager-alerts", User: "user", Password: "pass"},
labels: labels{Order: []string{"severity", "instance"},
Label: map[string]labelConfig{
- "severity:critical": {Priority: "5", Tags: []string{"rotating_light"}, Icon: "https://foo.com/critical.png"},
+ "severity:critical": {
+ Priority: "5",
+ Tags: []string{"rotating_light"},
+ Icon: "https://foo.com/critical.png",
+ emailAddress: "foo@bar.com",
+ },
"severity:info": {Priority: "1"},
"instance:example.com": {Tags: []string{"computer", "example"}},
},
M main.go => main.go +25 -8
@@ 46,14 46,15 @@ type alert struct {
}
type notification struct {
- title string
- body string
- priority string
- tags string
- icon string
- silenceBody string
- fingerprint string
- status string
+ title string
+ body string
+ priority string
+ tags string
+ icon string
+ emailAddress string
+ silenceBody string
+ fingerprint string
+ status string
}
func (br *bridge) singleAlertNotifications(p *payload) []*notification {
@@ 100,6 101,8 @@ func (br *bridge) singleAlertNotifications(p *payload) []*notification {
n.icon = br.cfg.resolved.Icon
}
+ n.emailAddress = br.cfg.ntfy.emailAddress
+
for _, labelName := range br.cfg.labels.Order {
val, ok := alert.Labels[labelName]
if !ok {
@@ 119,6 122,10 @@ func (br *bridge) singleAlertNotifications(p *payload) []*notification {
n.icon = labelConfig.Icon
}
+ if n.emailAddress == "" {
+ n.emailAddress = labelConfig.emailAddress
+ }
+
for _, val := range labelConfig.Tags {
if !sliceContains(tags, val) {
tags = append(tags, val)
@@ 197,6 204,8 @@ func (br *bridge) multiAlertNotification(p *payload) *notification {
n.icon = br.cfg.resolved.Icon
}
+ n.emailAddress = br.cfg.ntfy.emailAddress
+
for _, labelName := range br.cfg.labels.Order {
val, ok := p.CommonLabels[labelName]
if !ok {
@@ 216,6 225,10 @@ func (br *bridge) multiAlertNotification(p *payload) *notification {
n.icon = labelConfig.Icon
}
+ if n.emailAddress == "" {
+ n.emailAddress = labelConfig.emailAddress
+ }
+
for _, val := range labelConfig.Tags {
if !sliceContains(tags, val) {
tags = append(tags, val)
@@ 270,6 283,10 @@ func (br *bridge) publish(n *notification) error {
req.Header.Set("X-Tags", n.tags)
}
+ if n.emailAddress != "" {
+ req.Header.Set("X-Email", n.emailAddress)
+ }
+
if n.silenceBody != "" {
url := br.cfg.BaseURL + "/silences"