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
This commit is contained in:
co-authored by
Claude Opus 5
parent
428040d964
commit
36b15ddcaf
@@ -0,0 +1,68 @@
|
||||
# ADR 0001 — Rust, not Go
|
||||
|
||||
**Status:** Accepted, 2026-09-02. Supersedes the Go + embed-Mox design in
|
||||
[`../archive/ARCHITECTURE-go-embed-mox.md`](../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.
|
||||
Reference in New Issue
Block a user