Most "mailcow vs Stalwart vs Mailu" posts are written from a homelab: one domain, a handful of mailboxes, a feature checklist. That's a fine way to pick a server for your family. It tells you very little about what happens at 10,000 mailboxes, where the questions change from "does it have a spam filter" to "what happens when one node dies" and "how do I provision ten thousand accounts without clicking ten thousand times".
We run Stalwart for a university with 10,000 mailboxes (the cost side of that migration is in a separate write-up). So one of the three columns below comes from production. The other two don't. We have not run mailcow or Mailu at this scale, and where this article describes them, it's describing their official documentation, linked inline. Treat those parts as a reading of the docs, not as field notes.
The short version
| mailcow | Mailu | Stalwart | |
|---|---|---|---|
| Shape | Docker Compose stack: Postfix, Dovecot, SOGo, Rspamd, ClamAV, MariaDB, Redis, Nginx | Set of containers (Postfix, Dovecot, Rspamd, admin, webmail) | One Rust binary doing SMTP, IMAP, POP3, JMAP, CalDAV, CardDAV, WebDAV |
| Minimum RAM (per docs) | 6 GiB + 1 GiB swap | 1 GB without antivirus, 3 GB with ClamAV (+1 GB swap) | Depends on the stores you attach |
| Webmail | SOGo (with calendar, contacts, ActiveSync) | Roundcube or SnappyMail | None bundled for users; JMAP for building one |
| Storage | Local disk + MariaDB | Local volumes; external DB possible | Pluggable: RocksDB, PostgreSQL, MySQL, SQLite, FoundationDB; blobs in S3/Azure |
| Multi-node | No documented active-active mode; cold-standby via rsync | Community Helm chart, front-end replicas, needs RWX storage | Clustering in Community; read replicas and sharded stores in Enterprise |
| License | GPL-3.0 | MIT | AGPL-3.0, plus a commercial Enterprise license |
mailcow: the most complete box, and it is one box
mailcow is what most people mean when they say "self-hosted email that just works". According to its system requirements page, the default install wants at least 6 GiB of RAM plus 1 GiB of swap. The same page is refreshingly honest about why: a single SOGo worker can use around 350 MiB, and a company with 15 phones on ActiveSync and about 50 concurrent IMAP connections should plan for 16 GiB. ClamAV and the full-text search engine are the other big consumers, and both can be switched off.
What you get for that memory is a lot. SOGo gives users webmail, calendars, contacts and Exchange ActiveSync out of the box, which matters if you're replacing Exchange for people who live in Outlook on their phone. Mailbox migration is built into the admin UI as sync jobs, which run imapsync under the hood. The community is large, and most problems you'll hit have a forum thread already.
The limit for a large deployment is the shape. mailcow is a Compose stack meant to live on one host. We couldn't find a supported active-active or multi-node mode in its documentation; the redundancy story it does document is a cold standby, a consistent rsync copy to a second machine that you switch to when the first one dies. That's a reasonable design for a few hundred users. At 10,000, "restore to the standby" means an outage you have to schedule people around. The docs also rule out LXC, OpenVZ and Virtuozzo, so check your hosting before you start.
Mailu: small, tidy, and friendly to orchestration
Mailu is the lightest of the three on paper. Its requirements page asks for 1 GB of RAM and 1 GB of swap without antivirus, and 3 GB with ClamAV. Webmail is either Roundcube or SnappyMail, there's a REST API for the admin side, and the code is MIT-licensed, the most permissive of the three.
It's also the one that takes Kubernetes seriously as a deployment target, through a Helm chart. Read that chart's README before you plan around it. The front end can run as several replicas or as a DaemonSet, but running across nodes with the default single volume requires a storage class with ReadWriteMany access. Mailu's own docs point to the chart and note that they're looking for maintainers for it. Neither is a reason to avoid it. Both mean HA with Mailu depends on your storage layer at least as much as on Mailu itself.
Stalwart: what we actually ran into
Stalwart is a single binary written in Rust that speaks every mail and groupware protocol itself, instead of wiring Postfix to Dovecot. It's dual-licensed: AGPL-3.0 for the Community edition, and a commercial license for Enterprise. The reasons we picked it for a 10,000-mailbox migration off IceWarp were practical: JMAP (so we could build a webmail that doesn't feel like 2005, more on that in our JMAP piece), external storage, and a clustering path that doesn't require an enterprise contract.
Here's what running it looked like, including the parts that cost us time.
Storage is split, and that's the point
We keep metadata and settings in PostgreSQL and message blobs in S3-compatible object storage (MinIO). That split is what makes Stalwart workable at this size: PostgreSQL gets backed up and replicated like any other database, the blob store scales on its own, and no mailbox lives on one machine's local disk. It also means a PostgreSQL backup is a backup of the server's whole configuration, because since v0.16 the settings live in the database too.
Old guides will mislead you
Version 0.16 changed the configuration model. There's no big config.toml anymore. A small JSON file on disk describes only how to reach the datastore, and everything else (listeners, domains, DKIM, spam settings) is stored as objects in the database and managed through the web admin or the management API. Most tutorials you'll find online predate this, and following them produces errors that don't obviously point back to the cause. The management API is OAuth-protected with no password grant, so the very first setup is interactive, through a browser or a device-code flow.
Some settings weren't reachable on Community
We wanted a server-side send rate limit per user, so a compromised account talking raw SMTP couldn't blast out mail. On the Community build we ran (v0.16.8), we couldn't find a working way to apply it: --config only accepted the datastore JSON, the settings endpoints returned 404 even with a valid token, and editing the binary config rows in PostgreSQL directly wasn't a risk worth taking on a live mail server. We tested all of this on an isolated instance, not production. Our reading is that this part of settings management sits in Enterprise on that version, though Stalwart's public edition comparison doesn't spell it out line by line. We ended up rate-limiting in the webmail layer and at the reverse proxy in front of JMAP instead. If per-user sending limits are a hard requirement for you, test that exact setting on the Community edition before committing.
For the record, the comparison page does list what is Enterprise-only: multi-tenancy with per-tenant quotas, the AI/LLM spam classifier, account archiving and undelete, SCIM provisioning, read replicas and sharded stores, and the live dashboards and metric alerts. Basic clustering is in Community. Published Enterprise pricing is per mailbox per year, starting at €2.00 and dropping to €0.89 at higher volumes, so at 10,000 mailboxes it's a real line item but not an IceWarp-sized one.
Small things that bite on a restricted network
- On first start, the admin web UI is downloaded from GitHub. If your server can't reach GitHub, serve that file from somewhere it can reach.
- The submission port, 587, wasn't open by default in our install. Mail clients configured for 587 will fail to send until you add that listener.
- If you want a log file for your own tooling, configure a file tracer. In our Community build that worked through the JMAP management objects, unlike the rate-limit settings above.
Ten thousand accounts, and getting mail across
Creating accounts one by one isn't realistic at this size. The sane option is pointing Stalwart at the existing directory (LDAP/AD) so accounts come from the source of truth. For moving mail off IceWarp we used imapsync for messages and notes, and a small script of our own to copy calendars, contacts and files DAV-to-DAV, since both sides speak CalDAV/CardDAV/WebDAV. The awkward part wasn't Stalwart at all: IceWarp stores passwords hashed, so we couldn't just replay them. The workable approach was a temporary password per account for the duration of the copy, then restoring the original hash afterwards. Stalwart now also ships its own migration tool, Vandelay, which we didn't use, but it's worth a look before you script your own.
HA, as designed
Stalwart's Community clustering runs several independent nodes on the same shared stores, coordinated through a message bus. Our notes favored NATS over Redis pub/sub for coordination at this size, with HAProxy in front and the shared stores made redundant in their own right: PostgreSQL with a replica and failover, MinIO in distributed mode. That last part is where the actual work is. Stalwart clustering doesn't make a single PostgreSQL instance any less of a single point of failure.
So which one?
If you're under a few hundred users, want calendars and ActiveSync for phones without building anything, and a cold standby is an acceptable recovery plan, mailcow is the easy recommendation. It's mature and it's complete.
If you want the smallest footprint, an MIT license, or you already run Kubernetes and have ReadWriteMany storage you trust, Mailu fits well.
If you're at thousands of mailboxes, need the service to survive losing a node, want mail stored in systems you already know how to back up (PostgreSQL and S3), or want JMAP to build a proper web client on, Stalwart is the one we'd pick again. Go in knowing that v0.16's configuration model is new, older guides are wrong about it, and some admin features sit in the paid edition. Budget time to learn it on a test instance before your cutover weekend, not during it.
Whichever you pick, the server is usually not the hard part at this scale. Deliverability, DNS, directory sync and moving years of mail without losing flags are where the calendar goes. Why self-host at all in 2026 covers the other side of that decision.