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
2026-09-02 13:08:05 -07:00

OpenMail

An agent-native, self-hosted mail server, written in Rust.

One binary that gives an AI agent its own real email address — receive, parse, thread, search and send actual SMTP mail on infrastructure you control — behind a clean REST API and an MCP server. Humans and agents are both first-class users.

License Status

Status: v0.1, work in progress, not yet released. The workspace compiles and the domain model is taking shape; it does not yet send or receive mail. Follow docs/adr/0004-milestones.md.


Why this exists

The hard part of an agent-mailbox product was never the API. It is the mail plumbing: receiving over SMTP/MX, sending with real deliverability (SPF/DKIM/DMARC, DANE/MTA-STS, IP reputation), parsing genuinely broken MIME, threading, and storage.

Hosted agent-mail products solve this well and run on someone else's infrastructure, closed. The self-hostable mail servers that exist — Postfix+Dovecot, iRedMail, Stalwart — solve the plumbing but have no notion of an agent: no per-agent inbox provisioning, no threads as API resources, no MCP, no way for an agent to own a mailbox.

OpenMail is the intersection nobody occupies: agent-native, self-hostable, and permissively licensed.

What makes it agent-native

  • Inboxes are API resources, provisioned in one call — not Unix accounts.
  • Threads are first-class, stitched from In-Reply-To/References. An agent asks for a conversation, not a folder listing.
  • extracted_text — the reply with quoted history stripped. An agent that reads full bodies re-reads the whole thread every turn and burns its context window on text it already has.
  • MCP server — an agent owns and operates its own mailbox as tools.
  • Webhooks + WebSocket message.received events. Push, not poll.
  • Humans too — standard IMAP/SMTP access is a first-class goal, not an afterthought, so a person can point Apple Mail or Thunderbird at the same mailbox an agent is driving.

Why Rust, and why our own crates

Two implementations of the mail plumbing exist in a permissive licence: Mox (MIT, Go) and — for the primitives only — Stalwart's published crates (Apache-2.0/MIT, Rust). Stalwart's server is AGPL-3.0, which is why nobody has shipped a permissively licensed Rust mail server.

We are building one. See docs/adr/0001-rust.md for the decision and its honest costs.

Concretely, this means writing what the Rust ecosystem does not have. At the time of writing, dane and mta-sts do not exist on crates.io at all — Stalwart keeps its implementations inside AGPL server crates. Ours ship standalone and permissive, so any Rust mail project can use them.

The workspace

Twelve crates in three tiers. Tier 1 is published to crates.io as a contribution to the Rust mail ecosystem and depends on nothing else here.

Tier 1 — standalone, publishable

Crate What Prior art in Rust
mail-dane DANE / TLSA verification for SMTP (RFC 7672) none — first permissive implementation
mail-mta-sts MTA-STS policy discovery, fetch, parse, cache (RFC 8461) none — first permissive implementation
mail-dsn Delivery Status Notifications (RFC 3464) none

Tier 2 — the mail engine

Crate What
openmail-smtpd Inbound SMTP: session state machine, STARTTLS, AUTH, PIPELINING
openmail-relay Outbound: smarthost relays (SES, Oracle, generic) and direct-to-MX
openmail-guard Abuse gate: iprev, DNSBL, rate limiting
openmail-junk Per-inbox Bayesian spam classification

Tier 3 — the agent-native layer (the product)

Crate What
openmail-core Domain model, threading, quote-stripping. No I/O.
openmail-store Postgres metadata + S3-compatible blobs
openmail-api The v0 REST API
openmail-mcp MCP server
openmail The binary: serve, smtpd, sender, mcp, migrate

Third-party

mail-parser, mail-builder, mail-auth (DKIM/DKIM2/SPF/DMARC/ARC), smtp-proto — all Apache-2.0 OR MIT, all from Stalwart Labs' separately published primitive crates — plus hickory-resolver for DNS and DNSSEC.

No AGPL, GPL, or LGPL code is linked into any OpenMail binary. We use none of the Stalwart server. See NOTICE and docs/adr/0003-own-crates.md.

Sending: bring your own reputation, or build your own

Outbound sits behind one interface with two paths:

  • Relay — SES, Oracle Cloud Email Delivery, SendGrid, Postmark, Resend, or any smarthost. Rents someone else's IP reputation; inbox placement on day one. Providers are declarative data, not special cases — crates/openmail-relay/src/providers.rs.
  • Direct-to-MX — we resolve MX and deliver ourselves, with MTA-STS and DANE enforced. Our reputation, our control, and a months-long IP warmup.

Receiving is always ours.

⚠️ Oracle Cloud blocks outbound TCP/25 for tenancies created after 2021-06-23. Inbound :25 is unaffected. So on OCI you receive directly and relay outbound on 587 — direct-to-MX is not possible there at all. docs/adr/0005-oracle-cloud.md.

Build

cargo check --workspace     # ~21s cold on a Ryzen 7 5800X
cargo test  --workspace
cargo clippy --workspace --all-targets   # zero warnings is the gate

unsafe_code = "forbid" across the workspace. This code parses hostile input from the open internet on port 25; there is no exception worth the risk.

Licence

Apache-2.0. Permissive on purpose: the point is that other people can build commercial products on top of this, including ones that compete with anything we might host later. See docs/adr/0002-apache-2.md for why Apache-2.0 rather than MIT or AGPL.

S
Description
Agent-native, self-hosted mail server in Go. Embeds Mox as a library. MIT.
Readme Apache-2.0
198 KiB
Languages
Rust 81.5%
HTML 16.7%
Dockerfile 1.8%