-
Couldn't load subscription status.
- Fork 2.3k
feat: implement phantom_threading to group email alerts into threads #4623
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -265,6 +265,19 @@ func (n *Email) Notify(ctx context.Context, as ...*types.Alert) (bool, error) { | |
| fmt.Fprintf(buffer, "Message-Id: %s\r\n", fmt.Sprintf("<%d.%d@%s>", time.Now().UnixNano(), rand.Uint64(), n.hostname)) | ||
| } | ||
|
|
||
| if n.conf.PhantomThreading && len(as) > 0 { | ||
| // Add threading headers. All notifications for the same alert | ||
| // (identified by fingerprint) on the same day are threaded together. | ||
| // The thread root ID is a phantom Message-ID that doesn't correspond to | ||
| // any actual email. Email clients following the (commonly used) JWZ | ||
| // algorithm will create a dummy container to group these messages. | ||
| threadRootID := generateThreadRootID(as, n.hostname) | ||
| if threadRootID != "" { | ||
| fmt.Fprintf(buffer, "References: %s\r\n", threadRootID) | ||
| fmt.Fprintf(buffer, "In-Reply-To: %s\r\n", threadRootID) | ||
| } | ||
| } | ||
|
|
||
| multipartBuffer := &bytes.Buffer{} | ||
| multipartWriter := multipart.NewWriter(multipartBuffer) | ||
|
|
||
|
|
@@ -385,3 +398,18 @@ func (n *Email) getPassword() (string, error) { | |
| } | ||
| return string(n.conf.AuthPassword), nil | ||
| } | ||
|
|
||
| func generateThreadRootID(alerts []*types.Alert, hostname string) string { | ||
| if len(alerts) == 0 { | ||
| return "" | ||
| } | ||
|
|
||
| // Use first alert as representative of the alert group. | ||
| alert := alerts[0] | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Doesn't that mean even if we have 30 alerts, whatever the first one is, that's what will be used for fingerprinting? What if that alert resolves, but the other 29 remain? |
||
| fingerprint := alert.Fingerprint().String() | ||
|
|
||
| // Use current date so all mails for this alert today thread together. | ||
| date := time.Now().Format("2006-01-02") | ||
|
|
||
| return fmt.Sprintf("<alert-%s-%s@%s>", fingerprint, date, hostname) | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I assume this is where the name "Phantom Threading" comes from? I'm not sure people will understand that based on the name. Maybe "daily threading" would make more sense, although in that case what if we want to do a different threading strategy in the future?