Files
minstrel/internal/mailer/subject_test.go
T
bvandeusenandClaude Opus 5.5 63709a433d
release / govulncheck (push) Successful in 21s
release / web (push) Successful in 1m19s
release / go (push) Successful in 1m39s
release / integration (push) Successful in 5m27s
release / android (push) Successful in 5m47s
release / Build signed APK (releases and dev) (push) Successful in 5m34s
release / Attach APK to the Release (tag releases only) (push) Skipped
release / Build + push container image (push) Successful in 26s
release / Verify release artifacts (tag releases only) (push) Skipped
feat(notifications): grouped email digest, new music as a daily summary (#5346)
Nothing is emailed per event. New music (request_completed) goes out at
most once a day, at the summary hour in each user's own timezone, grouped
by artist. Everything else is batched: one email a window after the first
un-emailed item, holding whatever accumulated.

- Migration 0074: notification_email_settings (summary hour, batch window,
  admin-configurable) and user_notification_email_state (batch start, last
  sent, failures and retry_after per user and group). Existing rows are
  stamped emailed so the upgrade sends no backlog.
- The Notifier stamps emailed_at at write time when the recipient's email
  channel is off, so turning email on later doesn't send old items.
- Read rows are never selected. A row is stamped only after the mailer
  accepts, in one transaction with the state, against the read's clock, so
  a coalesced row updated mid-send stays pending.
- A failed send backs off 5m doubling to 6h; SMTP not configured just waits.
- Links come from the public address; without one the email has none.
- The mailer now RFC 2047-encodes subjects and strips line breaks from them.
- Admin → Integrations gains a Notification emails card.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 07:48:22 -04:00

26 lines
696 B
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package mailer
import (
"mime"
"strings"
"testing"
)
func TestEncodeSubject(t *testing.T) {
if got := encodeSubject("Minstrel: 2 updates"); got != "Minstrel: 2 updates" {
t.Errorf("plain ASCII changed: %q", got)
}
enc := encodeSubject("Minstrel: Moe Shop – WWW")
if !strings.HasPrefix(enc, "=?utf-8?q?") {
t.Errorf("non-ASCII not RFC 2047 encoded: %q", enc)
}
if dec, err := new(mime.WordDecoder).DecodeHeader(enc); err != nil || dec != "Minstrel: Moe Shop – WWW" {
t.Errorf("round trip = %q, %v", dec, err)
}
if got := encodeSubject("Hi\r\nBcc: everyone@example.com"); strings.ContainsAny(got, "\r\n") {
t.Errorf("a line break survived into the header: %q", got)
}
}