Skip to content

ADR-0006: Email into Matrix via Postmoogle, on the apex, over a Tailscale-wildcard zone

  • Status: Accepted
  • Date: 2026-07-14

Context

We wanted to receive email as Matrix messages (service mail, receipts, lists), complementing ntfy (outbound push, ADR-0005) and Mailpit (outbound viewer). Postmoogle (github.com/etkecc/postmoogle) is the fit: an SMTP server that posts incoming mail into rooms, 1 room = 1 mailbox, running as a plain Matrix bot (client-server API — no appservice registration, so it works with continuwuity). See docs/runbooks/email-to-matrix.md.

Two questions had to be settled: which mail domain, and how DNS serves the MX given the existing split-horizon.

  • Domain: the apex fmm.house was chosen over a mail. subdomain — cleaner addresses (you@fmm.house). Tradeoff: the apex becomes a mail domain, foreclosing a hosted email provider on fmm.house later. Switching providers is only a DNS cutover (addresses port), but apex mail is mutually exclusive with a real provider on the same name; a subdomain would have let both coexist. Accepted for a private homelab.
  • DNS: internal DNS uses AdGuard's DNS Rewrites UI (its "legacy" rewrite table), which handles A/AAAA/CNAME only and short-circuits all other record types — so it can't serve an MX, and a $dnsrewrite MX is shadowed by the name's A rewrite. Converting the apex A onto $dnsrewrite was attempted and rolled back: it risks the root A record, which also feeds Traefik's apex→www redirect, for no real gain.

Decision

  • Postmoogle on the apex. POSTMOOGLE_DOMAINS="fmm.house mail.fmm.house", SMTP on host :25, admin @albert, SQLite, joins matrix_default. Mailboxes are claimed per-room in Element.
  • No internal MX. LAN senders rely on implicit MX — apex A=.49 (the AdGuard rewrite) is the mail target; a standard MTA falls back to it when no MX exists. Simple senders use an explicit smarthost. Internal AdGuard rewrites are left as-is.
  • Public zone → Tailscale wildcard. In porkbun, *.fmm.house and the apex point at av's Tailscale AAAA (replacing the per-service records and the apex ALIAS → pixie.porkbun.com public forward). A public fmm.house MX 10 mail.fmm.house routes remote-tailnet mail. Traefik (reached over the tailnet) handles all HTTP routing, the apex→www redirect, and the wildcard cert.

Consequences

  • All *.fmm.house is tailnet-only publicly — non-tailnet visitors get an unroutable Tailscale address. The public apex→www forward is dropped (Traefik does it over the tailnet). Reversible: re-add the apex ALIAS and per-service records in porkbun.
  • No public inbound mail — external senders resolve the MX to a non-routable Tailscale address and fail, by design. Remote tailnet devices deliver fine.
  • The wildcard hides the service list publicly and exposes no new address (reuses the Tailscale AAAA already published via ha.fmm.house).
  • Bot password + POSTMOOGLE_DATA_SECRET (stacks/postmoogle/.env) and data/postmoogle.db join the backup scope (docs/runbooks/monitoring.md).
  • DNS-01 wildcard cert issuance is unaffected (uses _acme-challenge TXT, independent of A/AAAA).