Self-Hosted Mail Server (2026)
Self-Hosted Mail Server (2026)
Section titled “Self-Hosted Mail Server (2026)”Status of the irregulars.io community mail stack: production. Stalwart
0.15.5 on 46.110.152.206 (proxmox), with SOGo webmail at
mail.irregulars.io, transactional app mail via Cloudflare Workers send_email
binding from mail.irregulars.io subdomain, and inbound MX direct to Stalwart
(Cloudflare Email Routing decommissioned 2026-05-16).
This page documents what’s deployed, what the 2026 landscape looks like, and the SSO-integration considerations that drove the architecture decisions.
TL;DR (what’s running and why)
Section titled “TL;DR (what’s running and why)”| Layer | Service | URL / IP |
|---|---|---|
| Mailbox server (SMTP/IMAP/JMAP/Sieve) | Stalwart 0.15.5 | 46.110.152.206 (smtp/imap.irregulars.io) |
| Webmail | SOGo | https://mail.irregulars.io |
| Mail admin | Stalwart admin UI | https://mail-admin.irregulars.io |
| Inbound MX | Stalwart direct | irregulars.io MX 10 smtp.irregulars.io |
| Outbound (user clients) | Brevo SMTP relay | (transitional — direct from .206 after PTR is set) |
| Outbound (app transactional) | Cloudflare Workers send_email | binding in wrangler.toml |
| SSO / IdP | Authentik | https://sso.irregularchat.com |
Two important new realities in 2026:
-
Cloudflare now does BOTH inbound routing AND outbound sending. Email Routing has been around since 2022; Email Service went public beta in 2026 and lets Cloudflare Workers send transactional email via a
send_emailbinding. We use it for app-level transactional mail (meeting reminders, invites) but not for user mailboxes. -
App Passwords are now the standard pattern for OIDC + legacy clients. Stalwart 0.16.5, Mailcow, Mailu, and every modern self-hosted mail server either ships or supports app-password flows because mainstream clients (Apple Mail, Outlook, Thunderbird) don’t speak OAUTHBEARER/XOAUTH2 with third-party OAuth providers. SSO at the webmail/admin layer, App Passwords at the mail-client layer, is the canonical 2026 architecture.
What works today (irregulars.io)
Section titled “What works today (irregulars.io)”- ✅ Inbound mail to
*@irregulars.iois delivered to Stalwart mailboxes on.206. MX records point atsmtp.irregulars.io(resolves to.206). - ✅ Outbound from user clients routes through Brevo SMTP (clean reputation while PTR is pending for direct delivery).
- ✅ Outbound from apps (TeamCo meeting reminders, event-service guest
invites) goes via Cloudflare Workers
send_emailbinding from<service>@mail.irregulars.io. Seeapps/teamco/docs/EMAIL_SETUP.mdfor the per-worker setup. - ✅ SOGo webmail at https://mail.irregulars.io — TLS-protected via Cloudflare Tunnel.
- ✅ Stalwart admin at https://mail-admin.irregulars.io.
- ✅ TLS via Stalwart’s built-in ACME (Let’s Encrypt) for smtp/imap.irregulars.io.
- ✅ DKIM with selector
mail(mail._domainkey.irregulars.io) + inherited Brevo selectors during the transitional period. - ✅ SPF
v=spf1 ip4:46.110.152.206 include:_spf.brevo.com include:_spf.mx.cloudflare.net ~all— covers direct outbound, Brevo relay, and CF Email Service paths simultaneously. - ✅ DMARC
v=DMARC1; p=quarantine; rua=mailto:dmarc-reports@irregulars.io
What’s NOT done yet (open items)
Section titled “What’s NOT done yet (open items)”- PTR (reverse DNS) for
46.110.152.206— must bemail.irregulars.io. Open a ticket with Metronet business support. Without this, direct outbound from.206will be spam-foldered by Gmail/Microsoft. Keep Brevo as the outbound relay until PTR is confirmed. - Cut over from Brevo to direct outbound — remove
[queue.route.relay]and[queue.route.mx]config from Stalwart once PTR is in place. - Sieve forwarding rule for
sac@irregulars.io→issac@alfaren.xyzto replace the now-removed Cloudflare Email Routing rule. Set via SOGo’s Filters UI or the Stalwart admin sieve API. - SSO integration for mail clients — currently runs on Stalwart’s internal directory with separate passwords from Authentik. See “SSO integration patterns” below for the upgrade path to 0.16 App Passwords (recommended) or migration to Mailcow.
SSO integration patterns
Section titled “SSO integration patterns”The community’s hard requirement is that mail accounts integrate with Authentik SSO. There are three patterns, with different trade-offs:
Pattern A — App Passwords (Stalwart 0.16.5+, recommended)
Section titled “Pattern A — App Passwords (Stalwart 0.16.5+, recommended)”Architecture:
- Authentik is the source of truth for user identity.
- Stalwart’s primary directory is
oidc(Authentik). Users are auto- provisioned on first login. - Webmail (SOGo, Stalwart’s built-in WebUI) authenticates via OIDC → OAUTHBEARER tokens → Stalwart’s userinfo endpoint validates against Authentik. SSO experience preserved.
- For mail clients that don’t speak OAuth (Apple Mail, Outlook, Thunderbird, mobile): each user generates an App Password in Stalwart’s WebUI. The app password is unique to that client and can be scoped/revoked independently.
Why this is the modern best practice:
- It’s what Google, Microsoft, and Apple all do for legacy mail clients.
- Compromised app password ≠ compromised SSO identity (only that one client breaks).
- App passwords can be revoked individually, with expiration dates and IP restrictions (Stalwart 0.16.5+).
- Webmail still gets MFA + SSO benefits via the OIDC path.
Requirements:
- Upgrade Stalwart 0.15.5 → 0.16 (we’re currently on 0.15.5).
- Set
storage.directory = "authentik"(already configured). - In Authentik, configure the OAuth2 Provider’s
access_token_validityto ≥ 1h (currently set to hours=1 perstalwart-mailprovider, pk=21). - Users log into the Stalwart WebUI once via Authentik OIDC, then generate app passwords for each mail client.
Trade-off: Users have to set up app passwords. One-time effort per client per user.
Pattern B — Mailcow with native Authentik IdP (2025-03+)
Section titled “Pattern B — Mailcow with native Authentik IdP (2025-03+)”Architecture:
- Mailcow with IdP feature enabled (System → Configuration → Access → Identity Provider).
- Configure Authentik as the IdP. Mailcow auto-creates mailboxes on first OIDC login.
- Users authenticate to Mailcow’s SOGo/Roundcube via Authentik.
- For mail clients, users must create App Passwords (Mailcow’s built-in feature) — Mailcow forces this because Dovecot doesn’t natively speak OIDC for PLAIN auth.
Why this is interesting:
- Mailcow has had native Authentik integration shipped since 2025-03. No custom config needed — just point it at Authentik’s well-known endpoint.
- Bundled Rspamd (best-in-class spam filtering), ClamAV, SOGo, Roundcube, Dovecot, Postfix in one Docker Compose — opinionated and fully integrated.
- Web UI for everything (no CLI/config-file editing).
Trade-off:
- Migration cost from Stalwart: 1-2 days of careful work moving mailboxes, Sieve scripts, DKIM keys, ACME, and clients.
- More resource-heavy (~2 GB RAM vs Stalwart’s ~150 MB).
- Mailcow’s native IdP is functional but less polished than Mailcow’s own auth UI (Authentik branding shows up).
Pattern C — LDAP with Authentik-as-LDAP-outpost
Section titled “Pattern C — LDAP with Authentik-as-LDAP-outpost”Architecture:
- Authentik runs a built-in LDAP outpost (already in place at
ldap.irregularchat.com). - Mailcow / Mailu / Stalwart authenticates against LDAP.
- Users authenticate with their Authentik password directly (no OAuth flow needed for SMTP/IMAP).
Why this is interesting:
- Apple Mail, Outlook, Thunderbird all “just work” with LDAP-backed mail servers using PLAIN/LOGIN.
- Single password (Authentik) across SSO and mail.
- No app-password management UX needed.
Trade-off:
- Mail server has direct access to user passwords during auth (vs OAuth where it only sees tokens). Mitigated by TLS and short-lived password cache.
- LDAP doesn’t enforce MFA. Combined with SSO MFA at Authentik, this is a security gap: mail clients with valid Authentik password can bypass the MFA prompt that webmail requires.
- App passwords (Pattern A) solve this MFA bypass problem cleanly.
Recommendation: Pattern A (App Passwords on Stalwart 0.16.5) for our specific environment. It preserves SSO for webmail, fixes the legacy- client compatibility problem, and integrates MFA correctly. Pattern B (Mailcow) is the right call if we ever outgrow Stalwart’s web UI limitations or want bundled antivirus.
Reality check (updated 2026-05-17): Two upgrade attempts to Stalwart 0.16 in 24 hours, both blocked:
In-place TOML→JSON migration (2026-05-16): Stalwart 0.16 requires fresh-install +
STALWART_RECOVERY_ADMINenv-var bootstrap; old TOML config is ignored,stalwart-clibinary is gone,[authentication.fallback-admin]no longer honored. Reverted.Parallel deploy on
.205with proper bootstrap (2026-05-17): Got the entire stack standing — listeners, ACME-issued LE cert, OIDC directory pointing at Authentik, DKIM keys auto-generated, domain configured. Wizardx:Bootstrap/setreports “Setup complete” with admin credentials but never persists the admin to the RocksDB.x:Account/queryreturns empty after wizard. Matches upstream issue #3025. Recovery admin (env var) works but isn’t a real principal — can’t create users with credentials. Hard block.What we shipped instead (2026-05-17, working): Pattern A’ — a custom SASL auth proxy in front of Stalwart 0.15.5. Mail clients connect to
mail.irregulars.io:1993(IMAPS) or:1587(SMTP STARTTLS) withPLAINauth + a per-device app password. The proxy bcrypts the password locally, then connects upstream to Stalwart on:993/:587usingOAUTHBEARERwith a per-user Authentik OIDC access token (refreshed on each connection from a stored refresh token). SOGo’s existing OIDC integration is untouched.Per-device enrollment is a one-time browser OAuth flow:
python3 add-mail-creds.py <user> --label <device>→ user signs in to Authentik once → app password printed, ready to paste into Apple Mail. Revoke viapython3 revoke-mail-creds.py <user> --label <device>.Full operator guide:
selfhost/stalwart/sasl-proxy/README.md. Migration writeup:selfhost/stalwart/MIGRATION-TO-PUBLIC-IP-2026-05-16.md. v0.16 retry plan (for when upstream ships a fix):selfhost/stalwart/PLAN-v016-fresh-install.md.
Modern self-hosted mail server comparison (2026)
Section titled “Modern self-hosted mail server comparison (2026)”| Project | Language | Stack | Resource | OIDC/SSO | Spam | Notes |
|---|---|---|---|---|---|---|
| Stalwart | Rust | All-in-one (SMTP, IMAP, JMAP, Sieve, ManageSieve, CalDAV, CardDAV, WebDAV) | ~150 MB RAM | ✅ Native OIDC backend, App Passwords in 0.16+ | Built-in Bayesian + heuristics | What we run today. Best for resource-constrained or modern-protocol-focused deploys. |
| Mailcow | PHP + many containers | Postfix + Dovecot + Rspamd + ClamAV + SOGo + Roundcube + Solr | ~2 GB RAM | ✅ Native Authentik/OIDC since 2025-03 | Rspamd (best available) | Most feature-rich, most production-tested. Best for full-featured deployments. |
| Mailu | Python + many containers | Postfix + Dovecot + Rspamd + Roundcube | ~1 GB RAM | OIDC via reverse proxy or LDAP | Rspamd | Mature, similar to Mailcow but more modular. |
| Mox | Go | All-in-one (SMTP, IMAP, JMAP) | ~80 MB RAM | OAUTH2 in roadmap (not yet stable) | Built-in junk filter | Newest entrant, modern protocol stack (JMAP, MTA-STS, DANE), low-maintenance design philosophy. Not yet recommended for production — webmail is “early stages”. |
| docker-mailserver | Bash + Postfix/Dovecot | Postfix + Dovecot + Rspamd + Postscreen | ~500 MB RAM | LDAP only | Rspamd | Lower-level, ops-team-friendly. No web UI bundled. |
| iRedMail | Mixed | Postfix + Dovecot + Rspamd + Roundcube | ~1.5 GB RAM | LDAP, OIDC via proxy | Rspamd | Older but well-maintained. Free tier vs paid edition. |
| Poste.io | Mixed | Haraka + Dovecot + Rspamd | ~500 MB RAM | LDAP only | Rspamd | Was previously recommended in this wiki. Less active development than Mailcow. |
| Maddy | Go | SMTP + IMAP (LMTP) | ~50 MB RAM | LDAP | Custom | Lightweight, “composable” design. Smaller userbase. |
When to prefer each
Section titled “When to prefer each”- Pick Stalwart if: you want modern protocols (JMAP, CalDAV), low resource use, a single binary that handles everything including ACME, and you value a Rust-native security posture. App Passwords in 0.16 make it fully production-viable for mixed SSO/legacy-client environments.
- Pick Mailcow if: you want maximum compatibility with the larger ecosystem (Rspamd integrations, ClamAV updates, SOGo’s mature ActiveSync/CalDAV), and you have RAM to spare. The native Authentik IdP integration in 2025-03+ is genuinely well-done.
- Pick Mailu if: you want Mailcow-like features but more modular Docker Compose layout, or if you specifically need their granular RBAC.
- Pick Mox if: you’re greenfield and want the most modern stack — but expect rough edges on webmail and OIDC.
- Pick docker-mailserver / Poste.io / iRedMail if: you’re already comfortable with that platform. None of these have a strong case over the top three in 2026.
Cloudflare’s role in 2026
Section titled “Cloudflare’s role in 2026”Cloudflare has TWO email-related products now (post-2026 changes):
Email Routing (inbound, free since 2022)
Section titled “Email Routing (inbound, free since 2022)”Inbound MX service. You point your domain’s MX records at
route1/2/3.mx.cloudflare.net, configure rules in the dashboard, and CF
forwards mail to other addresses. Use cases:
- Forward
info@yourdomain.comto a personal Gmail account. - Catch-all to a single inbox.
- Drop spam at the edge before it hits your server.
What it can’t do: Deliver to your own SMTP server. There is no “deliver to SMTP” rule type. If you want self-hosted mailboxes, you have to bypass CF Email Routing on the MX layer.
We disabled it for irregulars.io on 2026-05-16 because we needed
test@irregulars.io and other addresses to land in Stalwart mailboxes.
Email Service / Email Sending (outbound, public beta in 2026)
Section titled “Email Service / Email Sending (outbound, public beta in 2026)”Cloudflare Workers can now send outbound mail via the send_email
binding. You add [[send_email]] name = "EMAIL" to wrangler.toml,
onboard mail.<your-domain> in the dashboard, and env.EMAIL.send(message)
delivers from CF’s infrastructure.
Use cases:
- Transactional mail from serverless apps (password resets, invites, notifications) without standing up SMTP infrastructure.
- Multi-app shared sender domain (we use
mail.irregulars.iofor TeamCo, future signal-bot, etc. — seeapps/teamco/docs/EMAIL_SETUP.mdfor the runbook).
Pricing: Workers Paid plan ($5/month) required. CF charges per message but is finalizing the model as of mid-2026.
What it can’t do: Host user mailboxes. There’s no IMAP for received mail. CF Email Service is a one-way SEND-only service.
Decision matrix — which Cloudflare option for which use case
Section titled “Decision matrix — which Cloudflare option for which use case”| Use case | Cloudflare service | Or self-host with |
|---|---|---|
Forward info@yourdomain.com → Gmail | Email Routing | Self-host with a forwarding rule |
| Send password-reset emails from Workers | Email Service send_email binding | None — this is CF’s killer use case |
User has a you@yourdomain.com mailbox they log into | Not supported by CF | Self-host (Stalwart, Mailcow, Mailu…) |
| Catch-all spam drop at the edge | Email Routing | rspamd at the mail server (more flexible) |
| Marketing newsletter sends | Not great fit — use Resend/Postmark/Brevo | — |
| Cron-driven transactional sends | Email Service | Stalwart’s queue or self-managed Postfix relay |
Architecture diagram (current irregulars.io, 2026-05-16)
Section titled “Architecture diagram (current irregulars.io, 2026-05-16)” Internet │ ┌──────────────────────────────┼──────────────────────────────┐ │ │ │ Inbound MX User clients (Apple Cloudflare │ Mail, mobile, etc.) Workers │ │ │ │ smtp.irregulars.io │ smtp/imap.irregulars.io │ send_email │ (MX 10) │ │ binding ▼ ▼ ▼ 46.110.152.206:25 46.110.152.206:465/587/993 CF Email Service (Stalwart MX listener) (Stalwart SMTP/IMAP) (delivers from CF │ │ edge servers) │ │ │ ▼ ▼ ▼ Mailbox routing Auth chain External recipients │ (currently: (Gmail, etc.) │ internal directory, │ PLAIN/LOGIN) ▼ │ Stalwart mailbox │ (sac@, test@, etc.) │ │ │ ▼ ▼ SOGo webmail Outbound queue (mail.irregulars.io) │ │ (PTR pending) │ ▼ Brevo SMTP (smtp-relay.brevo.com:587) │ ▼ Internet (recipient MX)Migration paths
Section titled “Migration paths”From current state → “ideal 2026”
Section titled “From current state → “ideal 2026””The path (revised 2026-05-17 after the SASL proxy ship):
-
Get PTR set for
46.110.152.206→mail.irregulars.io. Metronet business support ticket. Until done, keep Brevo. -
Switch outbound to direct — remove
[queue.route.relay]and[queue.route.mx]from Stalwart config. Stalwart does direct MX delivery from.206. -
Watch upstream Stalwart for a 0.16.6+ release that fixes
x:Bootstrap/set(#3025). The infrastructure to retry is already provisioned: IP.205, DNS reusable, ACME cert valid, DOCKER-USER firewall rules in place, Authentik provider has the signing key + offline_access scope. A 0.16.6 retry should be a 30-minute project. -
When 0.16 works: migrate users from saslproxy → native Stalwart App Passwords. Each user rotates their app password in Stalwart’s WebUI once, then revokes the saslproxy entry. Tear down
/datadrive/home/saslproxy/and deleteselfhost/stalwart/sasl-proxy/. -
Optionally: replace Brevo entirely for app sends by migrating TeamCo / event-service to direct SMTP at
mail.irregulars.io:587(using app passwords for the service accounts). CF Email Service remains an option but having a single mail server reduces moving parts.
Current working stack (2026-05-17, no migration needed):
| Mail client | Port | Auth |
|---|---|---|
| SOGo webmail | n/a (browser) | Authentik OIDC SSO |
| Apple Mail / iOS / Outlook | 1993 (IMAPS) + 1587 (STARTTLS) | App password via add-mail-creds.py |
| App transactional (TeamCo etc) | Cloudflare Workers send_email binding | n/a |
From Stalwart → Mailcow (if needed later)
Section titled “From Stalwart → Mailcow (if needed later)”If we decide Stalwart isn’t the right fit in 12 months:
- Stand up Mailcow on a separate host or proxmox VM.
- Configure Mailcow’s native Authentik IdP (System → Config → Access).
- Migrate mailboxes via
imapsyncper user. - Replicate DKIM keys (or generate new ones).
- Update DNS MX to point at Mailcow’s hostname.
- Decommission Stalwart.
Don’t do this preemptively — Stalwart 0.16.5 + App Passwords solves the core SSO + legacy-client problem. Mailcow’s advantage is Rspamd + the extended feature set (ActiveSync polish, ClamAV updates), not SSO.
Server-level auto-provisioning from Authentik (optional pattern)
Section titled “Server-level auto-provisioning from Authentik (optional pattern)”Independent of which mail server you pick, you can build out “create user in Authentik → mailbox appears on the mail server” auto-provisioning via:
Option 1 — Authentik SCIM provider → mail server SCIM endpoint
Section titled “Option 1 — Authentik SCIM provider → mail server SCIM endpoint”Authentik 2024+ supports SCIM 2.0 as an outbound provider. If the mail server has an SCIM endpoint:
- Stalwart: not yet (request open at github.com/stalwartlabs/mail-server/discussions). Workaround: use Authentik’s OIDC backend and let first-login auto-provision the mailbox.
- Mailcow: not native, third-party scripts exist.
- Authentik → custom Webhook → mail server’s admin API: this is the current best-effort pattern.
Option 2 — Authentik LDAP outpost → mail server’s LDAP integration
Section titled “Option 2 — Authentik LDAP outpost → mail server’s LDAP integration”Already running an LDAP outpost? Most mail servers (Mailcow, Mailu, Postfix-direct) support LDAP user backends. Users in Authentik appear in the mail server. No webhook needed.
Trade-off discussed in “Pattern C” above: LDAP doesn’t enforce MFA, so mail-client auth bypasses the MFA prompt webmail users get.
Option 3 — Auth-time auto-provision (what Stalwart and Mailcow do today)
Section titled “Option 3 — Auth-time auto-provision (what Stalwart and Mailcow do today)”User logs in via OIDC for the first time. The mail server’s OIDC directory creates a new principal on the fly using the email/username from the IdP. No SCIM, no LDAP, no webhook. Simplest and what we already use.
Recommended: Option 3 (auto-provision on first OIDC login). Reserve SCIM/LDAP for environments with hundreds of users where pre-provisioning matters.
Related guides in this wiki
Section titled “Related guides in this wiki”- Email Hardening Guide — SPF / DKIM / DMARC tuning, phishing defense, end-user practices.
- Cloudflare — DNS + Tunnel + Workers basics.
- Authentik Installation — the SSO/IdP this all integrates with.
- Self-Host Cloudflare Tunnels
— used to publish
mail.irregulars.iowebmail without exposing the origin IP. apps/teamco/docs/EMAIL_SETUP.md(monorepo) — runbook for app-transactional email via Cloudflare Workerssend_email.
References
Section titled “References”- Stalwart Labs — OpenID Connect docs
- Stalwart 0.16.5 release notes — App Passwords
- Stalwart — App Passwords
- Mailcow Authentik integration (community)
- Mailcow — External Identity Providers
- Authentik — Mailcow integration guide
- Mox — modern mail server in Go
- Cloudflare Email Routing docs
- Cloudflare Email Service docs (send_email binding)
- Cloudflare Email Service public beta announcement
- Privacy Guides — Self-Hosting Email comparison
- Mailflow Authority — Mailcow vs Postal vs Stalwart
- selfhosting.sh — Mailu vs Stalwart