Files
Karti TripathiandClaude Opus 5 36b15ddcaf Rewrite as a Rust, Apache-2.0 workspace
Supersedes the Go + embed-Mox design. The Go tree is removed; its
architecture doc is preserved at docs/archive/ARCHITECTURE-go-embed-mox.md
because its competitive analysis and data model still hold.

Five decisions recorded as ADRs:

  0001  Rust, not Go — accepting ~5,500 lines of protocol code that Mox
        would have given us free, to get the first permissively licensed
        Rust mail server. Costs stated plainly.
  0002  Apache-2.0, not MIT or AGPL — patent grant, trademark, CLA-free
        contribution. Public on GitHub; Gitea stays as the private fallback.
  0003  Stalwart's primitive crates (Apache-2.0/MIT) yes; its AGPL server
        crates never. DANE and MTA-STS sit on the AGPL side of that line,
        which is why we write our own.
  0004  Milestones, reordered: embedded inbound is required at launch.
  0005  Oracle Cloud blocks outbound :25, so direct-to-MX is impossible on
        the launch host. Split delivery is mandatory, not an on-ramp.

Twelve crates in three tiers. Tier 1 (mail-dane, mail-mta-sts, mail-dsn)
is standalone and publishable — no `dane` or `mta-sts` crate exists on
crates.io at all today.

openmail-relay ships the provider table as data, with SES and Oracle from
the start. Oracle's and Resend's SPF includes are deliberately None: a
guessed include turns the DNS check green against a mechanism the provider
does not honour, and mail still fails SPF silently.

cargo check/test/clippy/fmt all green; unsafe_code is forbidden workspace
wide; cargo-deny enforces the licence policy in CI.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JkyvfNJGTshJNE9FtwPLk7
2026-09-02 13:08:05 -07:00

2.6 KiB

ADR 0001 — Rust, not Go

Status: Accepted, 2026-09-02. Supersedes the Go + embed-Mox design in ../archive/ARCHITECTURE-go-embed-mox.md.

Context

The archived design chose Go in order to embed Mox (MIT) as a library, getting ~14,000 lines of production-tested mail correctness for free:

message 2,884   dkim 2,051   spf 1,560   smtpclient 2,012   junk 1,302
mtasts    703   dsn    771   dane   516   scram    796   sasl 327   …

The Rust ecosystem does not offer an equivalent. Stalwart is the only production Rust mail server and its server crates are AGPL-3.0-only OR LicenseRef-SEL, which we cannot use under Apache-2.0.

What Rust actually costs

Stalwart Labs publishes its primitives permissively (Apache-2.0 OR MIT), and those cover more than expected: mail-parser (MIME), mail-auth (DKIM1, DKIM2, ARC, SPF, DMARC, ARF, TLS-RPT), mail-builder, mail-send, smtp-proto. hickory-resolver covers DNS and DNSSEC.

What no permissive Rust crate provides, and we therefore write:

LOC (Mox equivalent) Rust prior art
DANE ~516 none on crates.io
MTA-STS ~703 none on crates.io
SMTP server session loop ~3,395 (go-smtp) smtp-proto parses only
DSN ~771 none
Junk (beyond a toy) ~1,302 bayespam has no training persistence
iprev / DNSBL / rate limit ~370 dnsbl crate abandoned since 2021

~5,500 lines of adversarial protocol code, versus zero in Go.

Decision

Rust. Accepted with eyes open.

Consequences

Negative, and stated plainly so nobody is surprised later:

  • v1 is roughly a quarter further out.
  • DANE and MTA-STS move from battle-tested to ours, and both fail silently: a DANE bug downgrades TLS without erroring; an MTA-STS bug defers mail nobody sees. That tail does not close at ship — it closes after enough strangers' mail has flowed through it.
  • Mitigation: every outcome in those crates is an explicit enum with no Default and no bool, so a caller cannot accidentally read "no policy" as "verified". See mail_dane::DaneResult.

Positive:

  • We ship the first permissively licensed DANE and MTA-STS in Rust, and the first permissively licensed Rust mail server.
  • mail-auth gives us DKIM2 and ARC, which Mox does not have.
  • One language for the mail engine and the agent layer.

Rejected alternative

Go now, Rust later, with the two crates published early to plant the flag at low cost. Rejected: it puts the strategic position — "the permissive Rust agent mail server" — behind a rewrite that would probably never be scheduled.