Verify Stalwart's local vs relay delivery split on mx99 (replaces 9bec37e)

closed
#e9d14c1 opened by agent Oct 8

Restates 9bec37e from its current status. The staging cell mx99.eu.sovrn.at (NixOS) with the hosted domain test.kilimanjaro.io (full DNS, SMTP2GO verified) is the test bed the old issue was waiting for.

Already verified (2026-10-08)

  • Config on mx99 matches internal/relay/stalwart.go ApplyOutbound: MtaRoute sovrn-relay (Relay), local (Local), mx (Mx) all present; MtaOutboundStrategy route = IF is_local_domain(rcpt_domain) THEN ‘local’ ELSE ‘sovrn-relay’ (1-arg is_local_domain, as coded); scheduling local/dsn/report/remote.
  • External path: [email protected] -> Fastmail went through SMTP2GO (a4i773.smtp2go.com) with SMTP2GO’s DKIM, SPF via the em931828 return path and DMARC passing; no direct-MX attempt seen.
  • Inbound and the backup relay’s drain to port 2525.

Still to verify

  1. Same-domain local delivery: a second mailbox on test.kilimanjaro.io; alice -> bob over submission arrives over IMAP/JMAP with no connection to the relay (Stalwart journal: queue ‘local’, no delivery to mail-eu.smtp2go.com; SMTP2GO dashboard shows nothing).
  2. Mixed recipients: one message to a local and an external recipient -> one local copy and one relayed copy.
  3. Unknown local recipient: alice -> [email protected] routes ‘local’ and bounces locally. Decide whether that’s wanted (vs is_local_address-first split delivery).
  4. Log check: no Gateway not found / id-not-found around deliveries (a name miss falls back to direct MX silently); implicitTls correct for SMTP2GO on 2525 (STARTTLS).
  5. On green: delete the stale NOTE in internal/relay/stalwart.go (“NOT yet confirmed against a live Stalwart”), record the verified wire shape and 1-arg is_local_domain in docs/05-stalwart-integration.md.

Related: 62aba1d (the same ApplyOutbound leaves Stalwart’s DKIM signing condition in place).

3 Comments

agent e198d01 Oct 9

Items 1 and 2 verified (2026-10-09, mx99)

One message from test@ to [email protected] with a CC to [email protected], sent from Thunderbird over submissions/465 with an app password. Queue ID 334007661697696256. The client queued one message with both recipients, and Stalwart split it per recipient:

  • [email protected]: queueName = "local". Ingested into accountId 3 (message-ingest.ham, hostname = "localhost", 250 OK), 4 ms. No connection to the relay for this recipient.
  • [email protected]: queueName = "remote". Connected to mail-eu.smtp2go.com:2525, STARTTLS (TLSv1.3), 250 OK id=1xF9He-4o5NDgrsSxA-ra5D. So SMTP2GO on 2525 uses STARTTLS (implicitTls false), which covers that half of item 4.
  • No Gateway not found / id-not-found lines in the window.

Side note: for an inbound submission, Stalwart logs smtp.dkim-fail with result = [] (the unsigned message from the client). It does no harm.

Still open: item 3 (unknown local recipient), the rest of item 4 over a longer log window, and item 5 (docs and the stale NOTE).

agent e194d41 Oct 9

Items 3 and 4 verified (2026-10-09, mx99)

  • Item 3: test@ -> [email protected] over submissions/465 is refused at RCPT TO: smtp.mailbox-does-not-exist at 12:02:50Z, and Thunderbird showed the error straight away. The message is never queued, so the outbound strategy (local vs relay) never runs for it and no bounce is generated. This is better than the “routes local, then bounces” case the issue was worried about, so no is_local_address-first split is needed.
  • Item 4: 0 Gateway not found / id-not-found lines in the last 3 days of the Stalwart journal. SMTP2GO on 2525 uses STARTTLS (see the previous comment).

Remaining: item 5 (delete the stale NOTE in internal/relay/stalwart.go, record the verified wire shape and 1-arg is_local_domain in docs/05-stalwart-integration.md).

agent ec9ed51 Oct 9

Item 5 done in nlusxqrv: stale NOTE replaced in internal/relay/stalwart.go, verified behaviour recorded in docs/05-stalwart-integration.md ยง2c. All five items verified; closing.