From 3dc2e09aeb3c2e8579ab5906271e4d0c532f299b Mon Sep 17 00:00:00 2001 From: Hein Date: Sun, 23 Aug 2026 11:00:17 +0200 Subject: [PATCH] fix(mail): add Message-ID to email messages --- server/internal/mail/mail.go | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/server/internal/mail/mail.go b/server/internal/mail/mail.go index 7a2d1e7..135e253 100644 --- a/server/internal/mail/mail.go +++ b/server/internal/mail/mail.go @@ -1,10 +1,13 @@ package mail import ( + "crypto/rand" + "encoding/hex" "fmt" "log" "net/smtp" "strings" + "time" "wedding-server/internal/config" "wedding-server/internal/store" @@ -18,6 +21,19 @@ func New(cfg config.EmailConfig) *Mailer { return &Mailer{cfg: cfg} } +// newMessageID builds an RFC 5322 Message-ID, scoped to the sender's own +// domain so it satisfies mail servers that reject messages lacking one. +func newMessageID(from string) string { + domain := "localhost" + if i := strings.LastIndex(from, "@"); i != -1 { + domain = strings.TrimSuffix(from[i+1:], ">") + } + + var buf [16]byte + _, _ = rand.Read(buf[:]) + return fmt.Sprintf("<%d.%s@%s>", time.Now().UnixNano(), hex.EncodeToString(buf[:]), domain) +} + func (m *Mailer) send(subject, body string) error { if m.cfg.SMTPHost == "" { log.Printf("mail: SMTP not configured, skipping email %q", subject) @@ -28,8 +44,8 @@ func (m *Mailer) send(subject, body string) error { auth := smtp.PlainAuth("", m.cfg.SMTPUser, m.cfg.SMTPPass, m.cfg.SMTPHost) msg := fmt.Sprintf( - "From: %s\r\nTo: %s\r\nSubject: %s\r\nContent-Type: text/plain; charset=UTF-8\r\n\r\n%s", - m.cfg.From, m.cfg.To, subject, body, + "From: %s\r\nTo: %s\r\nSubject: %s\r\nMessage-ID: %s\r\nDate: %s\r\nContent-Type: text/plain; charset=UTF-8\r\n\r\n%s", + m.cfg.From, m.cfg.To, subject, newMessageID(m.cfg.From), time.Now().Format(time.RFC1123Z), body, ) return smtp.SendMail(addr, auth, m.cfg.From, []string{m.cfg.To}, []byte(msg))