Repository: prometheus/alertmanager
File: notify/email/email.go (Go)

Code before:

	if _, ok := n.conf.Headers["Message-Id"]; !ok {
		fmt.Fprintf(buffer, "Message-Id: %s\r\n", fmt.Sprintf("<%d.%d@%s>", time.Now().UnixNano(), rand.Uint64(), n.hostname))
	}

	if n.conf.Threading.Enabled && len(as) > 0 {
		key, err := notify.ExtractGroupKey(ctx)
		if err != nil {
			return false, err
		}
		// Add threading headers. All notifications for the same alert group
		// (identified by key hash) are threaded together.
		threadBy := ""
		if n.conf.Threading.ThreadByDate != "none" {
			// ThreadByDate is 'daily':
			// Use current date so all mails for this alert today thread together.
			threadBy = time.Now().Format("2006-01-02")
		}
		keyHash := key.Hash()
		if len(keyHash) > 16 {
			keyHash = keyHash[:16]
		}
		// The thread root ID is a 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 := fmt.Sprintf("<alert-%s-%s@%s>", keyHash, threadBy, n.hostname)
		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)

	fmt.Fprintf(buffer, "Date: %s\r\n", time.Now().Format(time.RFC1123Z))
	fmt.Fprintf(buffer, "Content-Type: multipart/alternative;  boundary=%s\r\n", multipartWriter.Boundary())
	fmt.Fprintf(buffer, "MIME-Version: 1.0\r\n\r\n")

	// TODO: Add some useful headers here, such as URL of the alertmanager
	// and active/resolved.
	_, err = message.Write(buffer.Bytes())
	if err != nil {
		return false, fmt.Errorf("write headers: %w", err)
	}

	if len(n.conf.Text) > 0 {
		// Text template
		w, err := multipartWriter.CreatePart(textproto.MIMEHeader{
			"Content-Transfer-Encoding": {"quoted-printable"},
			"Content-Type":              {"text/plain; charset=UTF-8"},
		})
		if err != nil {

Review comment (suggestion):
ah, sorry again - caught on more thing! On re-read I noticed that `n.hostname` is included in the `threadRootID` - I don't think Alertmanager's hostname should be included in this. When in cluster mode, any Alertmanager node could send the notification. As written, we risk creating one-thread-per-node in the cluster. This shouldn't happen, as the selection of the node which sends the notification should be transparent to the user.

All this is to say that the `threadRootID` should be identical regardless of the node which computes it.

Code after:

	if _, ok := n.conf.Headers["Message-Id"]; !ok {
		fmt.Fprintf(buffer, "Message-Id: %s\r\n", fmt.Sprintf("<%d.%d@%s>", time.Now().UnixNano(), rand.Uint64(), n.hostname))
	}

	if n.conf.Threading.Enabled {
		key, err := notify.ExtractGroupKey(ctx)
		if err != nil {
			return false, err
		}
		// Add threading headers. All notifications for the same alert group
		// (identified by key hash) are threaded together.
		threadBy := ""
		if n.conf.Threading.ThreadByDate != "none" {
			// ThreadByDate is 'daily':
			// Use current date so all mails for this alert today thread together.
			threadBy = time.Now().Format("2006-01-02")
		}
		keyHash := key.Hash()
		if len(keyHash) > 16 {
			keyHash = keyHash[:16]
		}
		// The thread root ID is a 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 := fmt.Sprintf("<alert-%s-%s@alertmanager>", keyHash, threadBy)
		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)

	fmt.Fprintf(buffer, "Date: %s\r\n", time.Now().Format(time.RFC1123Z))
	fmt.Fprintf(buffer, "Content-Type: multipart/alternative;  boundary=%s\r\n", multipartWriter.Boundary())
	fmt.Fprintf(buffer, "MIME-Version: 1.0\r\n\r\n")

	// TODO: Add some useful headers here, such as URL of the alertmanager
	// and active/resolved.
	_, err = message.Write(buffer.Bytes())
	if err != nil {
		return false, fmt.Errorf("write headers: %w", err)
	}

	if len(n.conf.Text) > 0 {
		// Text template
		w, err := multipartWriter.CreatePart(textproto.MIMEHeader{
			"Content-Transfer-Encoding": {"quoted-printable"},
			"Content-Type":              {"text/plain; charset=UTF-8"},
		})
		if err != nil {