English · Tiếng Việt · 日本語 · 简体中文 · 繁體中文 · ไทย · Bahasa Indonesia · हिन्दी · Français · Español · Português · Русский
— English is authoritative, see TRANSLATIONS.md
Stop renting your inbox. A complete, self-hosted mail stack — Rust mail server, modern web client.
Freehold: property you own outright, with no landlord and no lease to renew. That is the difference between running this and renting a mailbox from someone whose business model is your data.
Mail server, webmail, and TLS termination — wired together, with an installer that generates your secrets and tells you exactly which DNS records to set. Optional SSO when you want it, absent when you don't.
Status: pre-1.0. The default edition has been tested end to end — a real message travels SMTP → mailbox → IMAP. The SSO edition starts and its database and OIDC discovery are verified on the Keycloak version actually shipped; the browser login flow is not. Read Known gaps before you rely on this.
The webmail ships a guided tour. This is that tour, recorded against a real stack — the
messages are delivered over SMTP and read back over IMAP by scripts/seed_demo.py, not
mocked:
Every image here is regenerated by script, never retouched — see
docs/media/README.md for the commands.
Self-hosting email is usually either a weekend of gluing together Postfix, Dovecot, Rspamd, and a webmail — or a hosted mailbox where someone else reads your metadata. Freehold Mail is the third option: one repo that assembles a modern stack you run yourself, on a machine you control. The mail server and webmail are memory-safe languages; nginx and PostgreSQL are C, so "memory-safe" describes the parts we chose, not the whole stack.
What it is: orchestration. Compose files, an nginx config, an installer, and honest docs. What it is not: a fork or a rewrite of anyone's mail server.
| Edition | Includes | Login | Tested E2E |
|---|---|---|---|
| Full Mail (default) | mail server + webmail + nginx | native username/password | ✅ yes |
| Mail + SSO | the above + Keycloak + PostgreSQL | OIDC/SSO |
You never touch Keycloak unless you want SSO; it lives in an optional overlay file.
Requirements: a Linux host with Docker and Compose v2, a domain you control, ports 25/465/587/993/80/443 reachable, and a TLS certificate.
git clone https://github.com/Novaza-ai/freeholdmail && cd freeholdmail
./install.shJust rented a server, or about to? Read
docs/HOSTING.mdfirst. It goes from a bare VPS to a working mailbox with a verification command at every step, and it names the one thing you cannot fix afterwards: most cheap providers block outbound port 25, which makes mail impossible no matter how well you configure this. It also has measured RAM, CPU and disk figures so you rent the right size rather than guessing.
The installer asks for your edition and domain, then:
- generates strong random secrets into
.env(mode 600,umask 077— nothing hardcoded); - pins the container images by digest;
- resolves your Let's Encrypt paths (the
live/symlinks don't work inside containers); - brings the stack up and prints the commands to create your first mailbox.
Then create a mailbox and log in at https://<your-domain>:
# domain, then user — the roles field is required, or SMTP AUTH refuses the account
curl -u admin:$STALWART_FALLBACK_ADMIN_SECRET -X POST http://127.0.0.1:8080/api/principal \
-H 'Content-Type: application/json' -d '{"type":"domain","name":"example.com"}'
curl -u admin:$STALWART_FALLBACK_ADMIN_SECRET -X POST http://127.0.0.1:8080/api/principal \
-H 'Content-Type: application/json' \
-d '{"type":"individual","name":"you@example.com","secrets":["<password>"],
"emails":["you@example.com"],"roles":["user"]}'Finally set your DNS records — docs/DNS.md has MX, SPF, DKIM, and DMARC.
Browser ─HTTPS─▶ nginx ─┬─ / and /api/* ─▶ Bulwark webmail (FE) :3000
├─ /jmap, /.well-known/jmap ─▶ Stalwart :8080/JMAP
└─ /.well-known/openid-configuration ─▶ Keycloak (SSO edition)
SMTP/IMAP clients ───────────────────────────────▶ Stalwart :25 :465 :587 :993
/api/* belongs to the webmail, which serves its own configuration and session routes
there. Only /jmap and JMAP discovery reach the mail server; its admin API is deliberately
not exposed through the proxy.
Every box is an independent, swappable container. Front end to back end is network only — JMAP over HTTP, no code linking. That boundary is what lets this repo be MIT while each component keeps its own license.
| Freehold Mail | Mailu / Mailcow | docker-mailserver | Google Workspace | |
|---|---|---|---|---|
| Mail server | Stalwart (Rust, JMAP-native) | Postfix + Dovecot | Postfix + Dovecot | — |
| RAM, idle (measured) | 218–288 MiB | mailcow: 6 GiB min (docs) | — | — |
| Webmail included | ✅ | ✅ | ❌ (bring your own) | ✅ |
| JMAP | ✅ | ❌ | ❌ | ❌ |
| SSO/OIDC | ✅ optional edition | partial | ❌ | ✅ |
| You hold the data | ✅ | ✅ | ✅ | ❌ |
| Maturity | pre-1.0 | mature | mature | commercial |
About that RAM row, because a comparison without its caveats is marketing. The
218–288 MiB is docker stats against this stack running idle, over two independent runs —
the range is published rather than the prettier single number because the two runs
disagreed by 32%. Reproduce it with docker stats --no-stream after docker compose up -d;
see docs/HOSTING.md. The 6 GiB is mailcow's own
documented minimum, not our
benchmark of it. And mailcow is heavier because it does more — ClamAV antivirus alone
accounts for roughly 1.3 GB, and SOGo adds CalDAV, CardDAV and ActiveSync. If you want
groupware and virus scanning, that 6 GiB is the honest price of those features and you
should pay it. The comparison is only fair for someone who wants mail, a web client, and
nothing else.
Mailu, Mailcow, and docker-mailserver are excellent and far more battle-tested. Pick Freehold Mail if you specifically want a JMAP-native, Rust mail server with webmail and optional SSO in one place — and note that the mail server is the Rust part: the webmail is TypeScript, and nginx and PostgreSQL are C.
Now: mailboxes, SMTP/IMAP/JMAP, webmail, TLS, optional SSO — a credible replacement for a hosted mailbox.
Not now: marketing/bulk email, newsletters, shared team inboxes, ticketing, migration tooling from other providers, or a managed control panel. Bulk sending in particular is a deliverability discipline, not a feature toggle — don't assume it.
Roadmap: see ROADMAP.md — near term is trustworthiness (SSO verified on
the shipped Keycloak, current upstream mail-server line, deliverability measured on a real
domain). Further out is Agentic Mail (v0.3): a stack a software
agent can be given safely — an MCP server over JMAP, and scoped, revocable per-agent
credentials instead of handing a bot your password. None of it is built yet, which is
why the milestone carries that name and the product does not. Contributions on the agent work are wanted —
see "Help wanted" in the roadmap.
- This repo (orchestration, config, installer, docs): MIT — see
LICENSE. - The programs it deploys keep their own licenses and are pulled as published
images; this repo contains none of their source:
- Stalwart Mail Server — AGPL-3.0-only OR SELv1 (dual-licensed; not "or later")
- Bulwark Webmail — AGPL-3.0-only
- Keycloak — Apache-2.0 (SSO edition)
- PostgreSQL — PostgreSQL License (SSO edition)
- nginx — BSD-2-Clause
If you modify Stalwart or Bulwark and serve it to others, AGPL requires you to
publish that component's modified source. Running the unmodified images does not.
Details: THIRD_PARTY_LICENSES.md and NOTICE.
Open relay is denied, submission requires authentication, and password mechanisms
(PLAIN/LOGIN) are only offered after STARTTLS. Each of these was measured against a
running stack. There
are also real weaknesses you must plan around, including an upstream admin API that
returns account passwords in cleartext. Read SECURITY.md before
exposing this to the internet.
Both are in the repo — you can reproduce every claim above yourself:
tests/test_config.sh # static: both editions validate, no secrets, digests pinned … (~seconds)
tests/test_e2e.sh # real: stack up → send a message → read it back over IMAP (~2 min)
tests/test_e2e.sh --sso # same, plus Keycloak + PostgreSQLtest_e2e.sh builds a throwaway stack on loopback-only ports with its own volumes and
container names, and tears it down on exit — it will not disturb a running deployment.
See tests/README.md, including what these tests deliberately do
not cover.
Day-2 operations — backups, certificate renewal, mailbox management, upgrades, incident
playbooks — are in docs/RUNBOOK.md. Prerequisites are in
docs/REQUIREMENTS.md.
See CONTRIBUTING.md. One house rule: claims about runtime
behaviour need measurements, not "works on my machine".
Who decides what, how to become a maintainer, and what happens to you if this project is
ever abandoned: GOVERNANCE.md. Who to expect a reply from, and an honest
statement of the bus factor: MAINTAINERS.md.
Led by Daika Ginza — GitHub · Substack · LinkedIn — with @anhkk1245, at Novaza Solution JSC.
We run this stack's components (Stalwart and Bulwark) in production for our own mail, and we
built Freehold Mail to package that architecture for anyone who wants to self-host it.
MIT-licensed; see LICENSE and NOTICE.
Full team, how decisions get made, and how to join:
MAINTAINERS.md · GOVERNANCE.md.
On commit authorship. Commits are authored by the person who made them, using an email verified on their GitHub account. Copyright is separate and does not change:
LICENSEandNOTICEname Novaza Solution JSC. Earlier commits were made under the company identity,Novaza Solution JSC <admin@novaza.ai>. That address is verified on no GitHub account for a while, so those commits were credited to nobody and the Contributors list showed onlydependabot. Verifying the address on a maintainer's account fixed all fifteen at once, without touching the commits. If you contribute, commit with an email verified on your own account and you will be credited.MAINTAINERS.mdhas the commands.
Not affiliated with Stalwart Labs, the Bulwark project, or Keycloak.

