freeholdmail
Health Warn
- License — License: MIT
- Description — Repository has a description
- Active repo — Last push 0 days ago
- Low visibility — Only 8 GitHub stars
Code Pass
- Code scan — Scanned 12 files during light audit, no dangerous patterns found
Permissions Pass
- Permissions — No dangerous permissions requested
No AI report is available for this listing yet.
Own your email. A complete self-hosted mail stack — Rust mail server, modern web client, optional SSO, and an optional MCP server that gives AI agents scoped, audited, revocable access to one mailbox. MIT orchestration around AGPL components.
English · Tiếng Việt · 日本語 · 简体中文 · 繁體中文 · ไทย · Bahasa Indonesia · हिन्दी · Français · Español · Português · Русский
— English is authoritative, see TRANSLATIONS.md
Freehold Mail
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.
See it work
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 — seedocs/media/README.md for the commands.
Why this exists
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.
Two editions
| Edition | Includes | Login | Tested E2E |
|---|---|---|---|
| Full Mail (default) | mail server + webmail + nginx | native username/password | ✅ yes |
| Mail + SSO | the above + Keycloak + PostgreSQL | OIDC/SSO | ⚠️ partial — stack starts, database and OIDC discovery verified on the shipped Keycloak 26.8.1 (15/15); the browser login round-trip is still not measured. See Known gaps |
You never touch Keycloak unless you want SSO; it lives in an optional overlay file.
For AI agents (optional, either edition): docker-compose.mcp.yml adds an
MCP server. You decide, per agent, which folders it sees,
whether it may draft, organise or send, and to whom. Every call is audited, revoking is one
edit, and the agent never holds your mailbox password. There is no delete tool.
Tested end to end (43/43); the threat model is in docs/MCP.md.
The clip below is 32 seconds long, has no sound, and was recorded against a local test stack. In it, a hostile email is
handed to the agent as data, a send to an address outside the allow-list is refused, an allowed
send arrives in the recipient's inbox, and every call is audited.
https://github.com/user-attachments/assets/d55bced5-6463-4e35-bffa-cd6964f8a066
Quickstart
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.sh
Just 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":"[email protected]","secrets":["<password>"],
"emails":["[email protected]"],"roles":["user"]}'
Finally set your DNS records — docs/DNS.md has MX, SPF, DKIM, and DMARC.
Architecture
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.
How it compares
| 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.
Scope, honestly
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). Then Agentic Mail (v0.3): a stack a software agent can be given safely. Its first
three pieces are built and tested: an MCP server over JMAP, scoped revocable per-agent
credentials, and an audit trail (docs/MCP.md). Agent sub-addressing is not
started. The project is still not named after it, because the product is a mail stack you
own, and the agent work is a tool you hand an agent on your terms. Contributions on the
agent work are wanted; see "Help wanted" in the roadmap.
⚖️ License
- 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.
Security
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.
Tests and operations
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 + PostgreSQL
tests/test_e2e.sh --mcp # same, plus the MCP server driven by a real MCP client
test_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.
Each of these runs, plus a mutation test that breaks the security checks one at a time
and a look at the mailbox afterwards, is recorded on video on a fresh clone.
Day-2 operations — backups, certificate renewal, mailbox management, upgrades, incident
playbooks — are in docs/RUNBOOK.md. Prerequisites are indocs/REQUIREMENTS.md.
Contributing
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.
Who builds this
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 <[email protected]>. 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.md
has the commands.
Not affiliated with Stalwart Labs, the Bulwark project, or Keycloak.
Reviews (0)
Sign in to leave a review.
Leave a reviewNo results found