Skip to content

Add direct-to-Google-Workspace / direct-to-Microsoft-365 relay delivery - #25

Draft
chrismuench wants to merge 1 commit into
mainfrom
feature/direct-mx-relay-providers
Draft

Add direct-to-Google-Workspace / direct-to-Microsoft-365 relay delivery#25
chrismuench wants to merge 1 commit into
mainfrom
feature/direct-mx-relay-providers

Conversation

@chrismuench

Copy link
Copy Markdown
Collaborator

Summary

Adds two new relay provider types that deliver mail directly to the recipient's own inbound mail server, so a routing rule for a self-hosted domain doesn't need to pay for or authenticate against a smart-host relay:

  • Google Workspace (direct) — no configuration at all. Google consolidated inbound MX onto a single hostname (smtp.google.com) shared by every Workspace domain, so it's always deliverable unauthenticated on port 25 with STARTTLS.
  • Microsoft 365 (direct) — one required field: the tenant's *.mail.protection.outlook.com MX hostname (found in the M365 admin center). Unlike Google's endpoint this is tenant-specific and can't be guessed, so the admin types it in. Also unauthenticated, port 25, STARTTLS.

Both reuse the existing MailKit SMTP transport (extracted the connect/send body out of SmtpProvider into a shared internal SmtpDelivery helper — behavior-preserving refactor) and are wired into the existing SmtpPortGuard so relays on Azure (which blocks outbound port 25) still get the existing clear rejection message instead of a silent connection failure.

No DB migration needed — RelayEntity.Provider is stored as a plain string, and the whole relay config UI/API is schema-driven (RelayProviderSchema), so this only touches the enum, the schema, the factory, and the UI's hand-maintained schema mirror (providers.ts) — no endpoint or form-component code changes.

Test plan

  • dotnet build — solution builds clean
  • dotnet test — all 4 test projects pass (381 tests), including new coverage:
    • RelayProviderFactoryTests — factory builds the right provider type for both new enum values
    • SmtpPortGuardTests — both new providers always flagged as port-25 regardless of settings
    • RelayProviderSchemaTests (new) — GoogleWorkspace has no fields, Microsoft365 requires exactly Host
    • Microsoft365ProviderTests (new) — throws when Host is unset, before any network I/O
  • UI: tsc -b typechecks clean, vite build succeeds
  • Not yet verified: an actual end-to-end send to a real Google Workspace or Microsoft 365 domain. That needs a real tenant/domain to test against, which wasn't available while building this — please test against a real domain before merging.
  • Manual UI smoke test (Relays → Add relay → confirm both new providers render correctly, one with zero fields, one with the Host field + help text)

🤖 Generated with Claude Code

…very

Routing rules can now point a domain at the recipient's own inbound mail
server instead of a paid relay: GoogleWorkspace delivers unauthenticated to
Google's unified inbound endpoint (smtp.google.com, fixed for every Workspace
domain), and Microsoft365 delivers unauthenticated to a tenant-supplied
*.mail.protection.outlook.com host. Both reuse the existing MailKit SMTP
transport (extracted into SmtpDelivery) and are wired into SmtpPortGuard so
the existing Azure port-25 block still applies.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant