Skip to content

Architecture ​

RustMail is a Cargo workspace with five crates, each with a single responsibility.

Crate Overview ​

CrateResponsibility
rustmail-smtpTCP listener, ESMTP handshake, hands each message to the server over a tokio mpsc channel and acknowledges it once stored
rustmail-storagesqlx + SQLite repository, FTS5 index, retention enforcement
rustmail-apiAxum routes and the WebSocket; bridges HTTP to storage and relays released mail
rustmail-serverBinary entry point: parses config, wires all crates, embeds UI assets
rustmail-tuiTerminal UI client (optional, connects to a running RustMail instance)

Data Flow ​

SMTP Client (your app)
    │
    ▼
rustmail-smtp
    │  tokio mpsc channel (Delivery)
    ▼
rustmail-storage
    │  event broadcast
    ▼
rustmail-api
    ├── REST endpoints  →  HTTP clients / CI pipelines
    └── WebSocket       →  Browser (SolidJS UI)

Key Design Decisions ​

DecisionRationale
Custom SMTP over samotopA mail catcher needs minimal ESMTP; samotop is over-engineered for this use case
sqlx over rusqliteAsync-native, compile-time checked queries
ULID over UUID/integerTime-sortable without needing a created_at index
SolidJS over Leptos/YewContributor-friendly (JS/TS), smaller bundles, better ecosystem
rust-embed for UISingle binary distribution: no separate static file server needed
Ephemeral mode via --ephemeralSame sqlx code path, just sqlite::memory: connection string

Frontend ​

The UI is a SolidJS + TypeScript + Tailwind CSS v4 application in the ui/ directory. At build time, Vite produces static assets that are embedded into the Rust binary via rust-embed. The server binary serves these at / with SPA fallback routing.

Build output: ~48 KB JS + ~11 KB CSS (gzipped).

Released under the MIT / Apache 2.0 License.