The Architecture of Mailwright
This article examines how one Rust process with strict internal boundaries replaces the composed mail stack, including the crate map, three structural rules, operator benefits, and tradeoffs.
Mailwright is a self-hosted mail and groupware server written in Rust and released under Apache-2.0. Its single binary supports SMTP, IMAP4rev2, POP3, JMAP, ManageSieve, and the CalDAV/CardDAV/WebDAV family. It also performs Sieve filtering and spam analysis during delivery, manages certificates through ACME, authenticates against an internal directory or OIDC, and provides one admin API with a corresponding operator CLI. This article describes the system's construction, its operational benefits, its relationship to other current approaches to running mail, and its design costs. It also addresses the project's youth directly.
Requirements for running mail
Self-hosted email has a justified reputation for difficulty, although the source is often misidentified. The individual protocols are old and well documented; the difficulty lies in composing them into a system.
A conventional self-hosted deployment consists of independently configured daemons connected manually. Postfix accepts and routes mail, while Dovecot serves IMAP and POP3 and usually receives local delivery over LMTP to keep its index files coherent. Rspamd or SpamAssassin scores inbound mail through Postfix's milter protocol, and DKIM signing occurs either in that spam filter or in a separate milter. Dovecot's Pigeonhole plugin provides Sieve filtering. Accounts are stored in MySQL or LDAP, and the separate lookup configurations that Postfix and Dovecot use for that store must remain consistent. Supporting calendars and contacts requires SOGo or Radicale, including its separate web stack and view of the user database, while webmail requires Roundcube. TLS requires certbot and a reload hook for each daemon that holds a certificate.
Each component performs its own function well. Postfix and Dovecot in particular have undergone decades of adversarial hardening, a record that no young project can credibly claim. However, the operator must maintain five or more configuration languages, a network of unix sockets and loopback ports, multiple log formats, and version combinations that were not tested as a unit. The failures that consume weekends rarely occur within a single daemon. They generally occur at boundaries such as the LMTP handoff, a milter timeout, the SASL socket between Postfix and Dovecot, or two lookup queries that have diverged.
This problem explains why Mailcow, Mailu, iRedMail, and docker-mailserver exist as appliance bundles. They place the same daemons behind Docker Compose and a settings layer, which does reduce the initial setup cost. However, this packaging does not alter the architecture. The existing interfaces remain and acquire additional container boundaries, so debugging still requires three terminals that follow three logs in three formats.
Integration as an architectural property
Mailwright is based on the premise that integration is an architectural property rather than a packaging property. Placing five daemons in one Compose file does not integrate them because their interfaces remain unchanged. Integration requires the components to share one configuration model, account authority, storage layer, telemetry stream, and lifecycle. It also requires their boundaries to be typed interfaces within a program instead of sockets between processes.
Both this idea and its principal objection are longstanding. Monoliths can become tangled, and mail servers have a particular history of tightly coupled codebases that cannot be changed safely. The relevant aspect of Mailwright's design is therefore not simply its use of one process, but the discipline that prevents the internals of that process from becoming undifferentiated.
The shape of the system
The workspace contains twenty-four crates in an acyclic dependency graph, grouped into the following roles.
Listener edge.
mailwright-tlshandles TLS acceptance, STARTTLS upgrades, and SNI certificate resolution for all protocol listeners.mailwright-acmeimplements RFC 8555 certificate issuance and renewal using HTTP-01 and TLS-ALPN-01 answerers. Certificate management therefore runs as a background server function instead of an external cron job.Mail transport.
mailwright-smtphandles SMTP and LMTP acceptance.mailwright-spamanalyzes each message once, whilemailwright-authverifies SPF, DKIM, DMARC, and ARC and produces RFC 8601 Authentication-Results for downstream consumers.mailwright-queueprovides a durable spool, retry scheduling, DKIM signing at the spool boundary, and DSN composition.mailwright-mtadetermines outbound routes, resolves MX records, and implements client-side SMTP.mailwright-deliveryperforms recipient resolution, folder provisioning, Sieve processing, and message placement.Mail access.
mailwright-imapimplements IMAP4rev2 with CONDSTORE, QRESYNC, and IDLE.mailwright-pop3implements the POP3 family of RFCs for the same mailboxes.mailwright-jmapimplements JMAP core and mail with push.mailwright-managesieveallows clients to manage their filter scripts under RFC 5804 and uses the same Sieve engine as delivery.Groupware.
mailwright-dav,mailwright-webdav, andmailwright-groupwareimplement WebDAV semantics, the CalDAV and CardDAV interfaces, and iTIP scheduling on the shared HTTP listener instead of a separate web stack.Management.
mailwright-httpprovides the single HTTP interface, including the listener, authentication layers, rate limiting, and admin API.mailwright-cliis a curated client for that API and the lifecycle of offline operations.Foundation.
mailwright-storespecifies the storage abstraction and mailbox model.mailwright-directoryserves as the account authority for principals, credential verification, SASL, group expansion, and the OAuth2 resource server.mailwright-configprovides configuration and an embedded expression language.mailwright-coordinatorprovides a pub/sub bus for cache coherence and wake-up hints.mailwright-telemetryemits typed, structured events throughtracing. Themailwrightcrate is the composition root and controls boot order, listener wiring, privilege drop, graceful drain, and backup entry points.
When a message arrives over TLS, the system scores and authenticates it once before delivering it through Sieve into the mailbox model. A coordinator event then signals any IMAP IDLE or JMAP push session monitoring that mailbox. All access protocols read the same store, authenticate against the same directory, and emit to the same telemetry stream. Consequently, no handoff in this path crosses a process boundary, uses a socket protocol, or requires a second configuration language.
Three rules for internal separation
Three structural rules govern the crate graph and address the risk that a monolith will become tangled.
Protocol crates never touch a storage backend. All persistence uses the role traits defined in mailwright-store. These comprise a data role, blob role, in-memory role, full-text role, and pub/sub role connected to a shared mailbox model. RocksDB and PostgreSQL currently implement these roles, and further tiers are designed to use the same traits. Because the IMAP server has no knowledge of the underlying backend, backends can be tested independently and selected according to deployment size. A single-box family server can use an embedded key-value store, while an operator can use PostgreSQL when they want state in a database they already know how to back up.
Every cross-crate seam is a trait object. The SMTP server passes accepted messages to a MessageSink, and the queue passes outbound work to a RelaySink. Spam analysis connects through a SpamHook, account lookups go through Directory, and cross-node events go through PubSub. Each crate therefore depends on a contract instead of a sibling's implementation, which allows tests to exercise a subsystem with fakes at every boundary. These boundaries correspond to the sockets and milter connections in a composed stack. In Mailwright, the compiler checks both sides of each contract, so a version mismatch is detected as a build failure instead of causing an outage on a Tuesday night.
There is exactly one composition root. Only the mailwright crate constructs the system. It reads configuration, determines boot order, binds listeners, drops privileges, and controls graceful drain and teardown. No subsystem starts another subsystem. This restriction keeps the dependency graph acyclic in practice because any shortcut between two subsystems must pass through the root, where reviewers can see it.
These rules use the same interface discipline found in any well-managed service codebase. Applying that discipline within one process gives the operator the integration benefits of a monolith while avoiding the internal coupling that made older integrated mail servers difficult to trust.
What the operator gets
The purpose of this architecture is operational, and its consequences can be stated concretely.
A single configuration model governs the system. Every subsystem uses one file format and one embedded expression language. A routing decision, spam threshold, and rate limit are therefore expressed in the same form and can refer to the same values. The equivalent composed stack uses Postfix syntax, Dovecot syntax, UCL, and the DAV server's syntax without shared variables.
The directory is the sole account authority. SMTP consults the directory for recipient validation, every access protocol uses it for authentication, and the admin interface uses it for management. Because no second copy of the user table can diverge, OIDC or OAuth2 bearer authentication can be added in one place for all protocols simultaneously.
The server has a unified lifecycle. The server uses a defined boot order, drains gracefully, restarts with low downtime, applies schema migrations behind a gate, and performs online backups through entry points that understand the storage roles. An upgrade therefore consists of one unit and one changelog instead of a compatibility matrix for five projects with independent release cadences.
Telemetry uses a single stream. Every subsystem emits typed, structured events into a shared catalogue. For a deferred message, the SMTP reception, spam verdict, queue decision, and eventual delivery appear in one stream with a common vocabulary. This replaces four log formats that must be correlated by timestamp and inference.
The protocols remain coherent. Because all protocols share one mailbox model, cross-protocol behavior can be correct by construction rather than by convention. For example, POP3's delete-on-QUIT semantics remain consistent with IMAP's view of the same INBOX because both use one maildrop. In a composed system, this behavior depends on two daemons interpreting a shared maildir identically.
Comparison with alternative architectures
The composed stack offers decades of hardening and effectively unlimited flexibility, but it also introduces interfaces and configuration surface. For operators with sufficient operational capacity and existing investment, Postfix and Dovecot remain excellent choices, and Mailwright's design argument does not diminish them. The relevant question is where the total cost of ownership accrues.
Mailwright and the bundles share the goal of providing a mail system that can be established in an afternoon, but they use different methods. A bundle retains every interface in its packaged stack and adds another layer. A failure therefore requires debugging both the stack and the bundle, whereas Mailwright is based on removing those interfaces rather than wrapping them.
Compared with integrated suites such as Zimbra and the Kopano/grommunio lineage, Mailwright reflects a different generation of design. It uses a single Rust binary with role-based storage rather than a large multi-service Java or C deployment, Apache-2.0 rather than licensing models that have shifted under their users, and JMAP and modern DAV rather than protocol surfaces accumulated over twenty years. These suites demonstrate demand for integrated mail and groupware, while also showing how large the integrated model becomes without strict internal boundaries.
Among modern single-binary servers, Mailwright is closest in approach to Maddy and mox but differs in scope. Both are well-regarded Go servers that demonstrate the one-process model, and both are limited to mail. Mailwright holds that, for people who continue to pay for hosted suites, an "email server" includes calendars, contacts, and scheduling. It therefore places JMAP and the DAV family in the same process and storage model as mail instead of a separate sidecar with its own user database.
The tradeoffs
The design also has substantive costs that must be included in its evaluation.
One process creates a shared failure domain. A composed stack isolates DAV from SMTP, so a DAV server crash does not stop SMTP. In Mailwright, a sufficiently severe defect could stop both. Rust's memory safety eliminates an important class of these defects, and crate boundaries restrict logical coupling. However, process isolation provides a stronger guarantee than either measure, and the composed stack has that isolation.
The system is upgraded as one unit. An operator cannot retain an earlier IMAP server while upgrading the spam engine. Coupled upgrades eliminate the version matrix and are central to the design, but they reduce flexibility. This affects operators who depend on pinning one component while updating another.
The project lacks the pedigree of established systems. Postfix has faced attacks on the public internet for twenty-five years. Rspamd's rules and community corpus embody accumulated experience that a young analysis engine cannot reproduce through a shortcut. Mailwright is alpha, so its architecture is an argument about where mail servers should go rather than a claim to battle testing it has not accumulated.
Mailwright does not bundle webmail. Existing bundles include Roundcube or SOGo, which many operators specifically require. Mailwright serves protocols and provides JMAP for modern clients, but an operator who requires a browser mailbox from the first day must deploy one separately. This remains a substantive gap in its current all-in-one offering.
The project is responsible for every protocol. The integrated approach requires simultaneous competence in SMTP, IMAP, JMAP, Sieve, iCalendar scheduling, and WebDAV semantics, each of which is a distinct specialty. The mitigation consists of conformance tests that exercise the real binary over the wire and a documented record of every deliberate divergence from the governing RFCs. Nevertheless, the interface surface is enormous and provides the appropriate basis for evaluating the project's pace.
Who this is for
Mailwright is intended for an operator who wants mail, calendars, contacts, filtering, and spam defence on hardware they control, providing the scope of a hosted suite without the need to assemble and maintain a five-daemon distributed system. Its product is defined by an architecture that uses one process, configuration, directory, store, and telemetry stream, with sufficiently strict internal boundaries to keep the monolith maintainable. Its costs include shared fate, coupled upgrades, and the appropriate caution for a young codebase compared with twenty-five-year-old daemons.
The composed stack will remain appropriate for many deployments. Its dominance, however, results as much from historical contingency as from deliberate design. Mail developed as separate programs on multi-user Unix systems, where separate programs provided the only available modularity. Typed interfaces within one address space also provide modularity, and they impose stricter contracts than sockets. Mailwright is based on the proposition that these interfaces are better suited to self-hosted mail.