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, emits parsed messages over a tokio broadcast channel
rustmail-storagesqlx + SQLite repository, FTS5 index, retention enforcement
rustmail-apiAxum routes, WebSocket broadcast, bridges HTTP to storage and SMTP channel
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 broadcast channel (ReceivedMessage)

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: ~28 KB JS + ~13 KB CSS (gzipped).

Released under the MIT / Apache 2.0 License.