Closes the "advanced routing rules" roadmap item. Previously resolveInboundAddress
only ever matched an exact mailbox or alias and hard-coded action "store", so the
forward/reject branches downstream were unreachable and catch-all addresses were
impossible.
Domain rules now resolve in three phases, which is what stops a `*` catch-all
from shadowing real mailboxes:
1. reject rules, evaluated before any mailbox lookup so a sender can be blocked
even when the recipient is a real mailbox
2. exact mailbox, then multi-domain mailbox aliases
3. remaining forward/store rules as the catch-all fallback
Within each phase rules run by descending priority, then oldest first.
forward and reject are actioned in the Worker `email` handler rather than the
inbound queue consumer, because message.forward() and message.setReject() only
exist on the live ForwardableEmailMessage. A forward drops the message unless the
rule keeps a copy, and a failed forward still stores the message so mail is never
silently lost. Regex patterns are guarded so an invalid pattern cannot throw and
take down inbound processing.
The existing mailbox-scope rules are unchanged in behaviour; both queries now
filter on scope so the two kinds never leak into each other's UI.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PGeWDVSkXtVEmDAN2AtB9h