diff --git a/services/notifications/pkg/channels/channels.go b/services/notifications/pkg/channels/channels.go index 5430f4a467..eb42af5f69 100644 --- a/services/notifications/pkg/channels/channels.go +++ b/services/notifications/pkg/channels/channels.go @@ -3,9 +3,12 @@ package channels import ( "context" + "crypto/rand" "crypto/tls" + "fmt" stdmail "net/mail" "strings" + "time" "github.com/pkg/errors" mail "github.com/xhit/go-simple-mail/v2" @@ -118,6 +121,7 @@ func (m Mail) SendMessage(_ context.Context, message *Message) error { email := mail.NewMSG() email.SetFrom(appendSender(message.Sender, m.smtpAddress)).AddTo(message.Recipient...) email.SetSubject(message.Subject) + email.AddHeader("Message-ID", generateMessageID(m.smtpAddress.Address)) email.SetBody(mail.TextPlain, message.TextBody) if message.HTMLBody != "" { email.AddAlternative(mail.TextHTML, message.HTMLBody) @@ -135,3 +139,22 @@ func appendSender(sender string, a stdmail.Address) string { } return a.String() } + +// generateMessageID generates a unique Message-ID header value according to RFC 5322 +func generateMessageID(domain string) string { + // Extract domain from email address if it contains @ + if idx := strings.LastIndex(domain, "@"); idx != -1 { + domain = domain[idx+1:] + } + + // Generate random bytes for uniqueness + b := make([]byte, 16) + if _, err := rand.Read(b); err != nil { + // Fallback to timestamp-based ID if random fails + return fmt.Sprintf("<%d@%s>", time.Now().UnixNano(), domain) + } + + // Create Message-ID: + timestamp := time.Now().Unix() + return fmt.Sprintf("<%d.%x@%s>", timestamp, b, domain) +}