Category
Chat, mail and notifications: what is worth self-hosting and what is not
One thing in this category costs 30 MB and works forever. Another can silently stop delivering your mail to Gmail and give you no way to earn the reputation back.
Self-hosted mail is a reputation problem wearing a software costume#
Every guide to self-hosted mail is written as though the difficulty is configuring Postfix. It is not. mailcow: dockerized and Stalwart both solve the software problem completely, and neither touches the actual one.
Answer three questions before you install anything. Can you open outbound port 25? Most residential ISPs block it, and several major clouds block it by default. Can you set a PTR record that matches your mail hostname exactly, for IPv4 and IPv6 both? That is a control panel setting at whoever owns the IP block, not a record in your DNS zone, and a mismatch is the most common reason a correct mail server is rejected by Outlook and Gmail. Is your IP range already on the usual blocklists? A fresh address has no sending reputation, which means weeks of greylisting even when everything is right.
If any answer is no, stop. And understand the failure mode you are signing up for, because it is not an outage. Your stack stays green, your logs stay clean, and your mail is silently discarded at the far end. You learn about it when a customer says they never received the invoice. Reputation is earned by sending volume over time and cannot be purchased back.
Who should still do it#
Someone with a static IP, a PTR record they control, and a business reason: leaving Microsoft 365 for cost or jurisdiction, or wanting SOGo webmail, calendar and contacts on the same box as IMAP. That person should run mailcow, budget the documented 6 GiB plus 1 GiB of swap and 20 GiB of disk before any mail exists, and back up the crypt volume in the same run as vmail, because Dovecot's mail-crypt keys live in crypt and a vmail backup without them restores as unreadable ciphertext.
Everyone else should take the hybrid: host receipt, filtering and storage, relay outbound through Postmark, SES or Mailjet. You keep your archive on your disk and hand the unwinnable part to someone whose full-time job it is.
The default#
Start with notifications, because they are the genuinely good part of this category. ntfy is one container, roughly 30 MB idle, and curl -d "backup done" https://ntfy.example.com/alerts is the entire integration for cron jobs, Uptime Kuma, Home Assistant and your backup scripts. It has an official iOS app, which is the deciding fact for most households.
Two situations where that is the wrong pick. Android-only, and you want per-sender revocation: Gotify gives every sender its own application token in 20 MB, where ntfy's model is that the topic name is the credential. You need a chat server, not alerts: Mattermost for a private team on PostgreSQL 14 or newer, Synapse only if federating with other people's servers is the actual requirement.
The mistakes#
- Leaving ntfy at its defaults. A fresh install has no authentication and
auth-default-accessisread-write, so every topic on your server is world-readable and world-writable. Setdeny-alland grant withntfy accessbefore you point a door sensor at it. - Gotify's
admin/admin.GOTIFY_DEFAULTUSER_*is read only when the first user is created, so setting it later does nothing and people assume they are covered. - Upgrading Debian 12 to 13 under mailcow. It can pull in Exim, which binds port 25 and stops Postfix accepting inbound mail. Check
ss -lntp | grep :25after any host distribution upgrade. - Creating Synapse's database without
--locale=C --template=template0. Synapse refuses to start, or you setallow_unsafe_localeand get subtly wrong string ordering that surfaces later as missing events. - Serving Matrix on 443 without
/.well-known/matrix/server. Your own clients work perfectly while no other homeserver can reach you. The symptom is invitations that never arrive. - Assuming Mattermost history is safe. The Entry edition's 10,000 message limit is server-wide and silent: older posts stay in the database and stop being searchable.
Read next#
ntfy vs Gotify settles the push decision in detail, and mailcow vs Stalwart the mail one. Replace Gmail walks the hybrid migration, Replace Slack the chat one. Before you commit to mail at all, read When not to self-host and DNS for self-hosters, in that order.
Every communication tool we profile#
Sorted by operational load, lightest commitment first. Every row links to a full profile with the resource numbers, the upgrade traps and the restore path.
| Tool | Ops load | Idle RAM | Licence | Identity | Backup shape |
|---|---|---|---|---|---|
| Gotify | 1, Set and forget | 20 MB | MIT | Native OIDC | SQLite backup |
| ntfy | 1, Set and forget | 30 MB | Apache-2.0 (dual licensed with GPL-2.0) | Local accounts only | SQLite backup |
| Mattermost | 3, Moderate | 500 MB | AGPL-3.0 core, Mattermost Source Available License for `server/enterprise/`, Apache-2.0 for webapp and admin tools, MIT for official binaries | Native OIDC | Postgres dump |
| Stalwart | 3, Moderate | 150 MB | AGPL-3.0 for the Community edition, dual licensed with the proprietary Stalwart Enterprise License for gated features | LDAP only | Embedded key-value store |
| Synapse | 4, Heavy | 700 MB | AGPL-3.0-only (or a commercial license from Element) | Native OIDC | Postgres dump |
| mailcow: dockerized | 4, Heavy | 3500 MB | GPL-3.0 for mailcow's own code; bundled components keep their own licenses | Native OIDC | MySQL dump |
Profiles#
Gotify
A 20 MB push server with real tokens, an Android app, and no iOS client
ops 1/5 · 30 MBntfy
Push notifications by HTTP POST to a topic, with no account and no client registration
ops 3/5 · 500 MBMattermost
Self-hosted team chat shaped like Slack, with free tiers that narrowed sharply in v11
ops 3/5 · 150 MBStalwart
One Rust binary that is SMTP, IMAP, JMAP, CalDAV and CardDAV at the same time
ops 4/5 · 700 MBSynapse
Reference Matrix homeserver: AGPL since 2024, and still what federation is tested against
ops 4/5 · 3500 MBmailcow: dockerized
A complete mail server in 18 containers, with a UI that makes it survivable
Head to head in this category#
- mailcow vs StalwartA mature multi-container stack against a single Rust binary. Neither one fixes the part that actually fails.
- ntfy vs GotifyTopic names as passwords and an iOS app, or per-sender tokens and Android only. Pick on phones first.
Leaving a cloud service in this category#
- Replace GmailThe one migration on this site we mostly recommend against. Read the failure mode before you buy a VPS.
- Replace SlackSlack's free plan hides messages at 90 days and deletes them at one year. Get out properly, or do not bother.
Questions#
Can I self-host email on my home connection?
Almost certainly not for outbound. Most residential ISPs block outbound port 25, several major cloud providers block it by default, and you cannot set a PTR record for an address you do not own, which is a control panel setting at whoever holds the IP block. A missing or mismatched PTR is the single most common reason a technically perfect mail server gets rejected by Outlook and Gmail. Receiving mail is genuinely easy. Sending it so that it lands in an inbox is the entire job, and no software in this category changes that.
What happens when self-hosted mail stops working?
Usually nothing visible. Your stack stays green, your logs look fine, and messages you send are quietly binned or greylisted at the far end. You find out days later when someone says they never got it. The recovery is slow because sending reputation is earned by volume over time and cannot be bought back. This is the argument for the hybrid shape: run receipt, filtering and storage yourself, and relay outbound through Postmark, SES or Mailjet so a reputation problem is somebody else's full-time job.
mailcow or Stalwart?
mailcow is 18 containers (Postfix, Dovecot, Rspamd, ClamAV, SOGo, MariaDB, Redis and the rest) with a documented minimum of 6 GiB plus 1 GiB swap and 20 GiB of disk before any mail arrives. Stalwart is one Rust binary covering SMTP, IMAP, JMAP, CalDAV and CardDAV, idling near 150 MB. Pick mailcow for the best-documented path and a UI that manages DKIM, aliases and quotas. Pick Stalwart if 18 containers is absurd for one domain, and check the Enterprise split first: third-party OIDC login, multi-tenancy and deleted-mail recovery are paid.
ntfy or Gotify?
ntfy for most households. curl -d "backup done" ntfy.sh/mytopic works with no account and no token, there is an official iOS app, and you can start on the hosted instance and move to your own server without changing a publish call. Gotify is stricter and smaller: 20 MB, every sender gets a revocable application token, nothing is readable without one. Gotify has never had an official iOS app and there is no hosted instance holding an Apple push certificate, so if anyone in the house uses an iPhone that decision is already made.
Does self-hosted push actually work on an iPhone?
With ntfy, yes, with one caveat. Apple only delivers push through APNs and your server has no APNs certificate, so you set upstream-base-url: "https://ntfy.sh". Your server then publishes a poll_request containing only a message ID to ntfy.sh, which wakes the app through APNs, and the app fetches the body from you. Without that setting, notifications arrive 20 to 30 minutes late or worse. The message body never transits a third party, but the wake-up does, and the maintainer describes the iOS app as bare bones.
Should I run Matrix or Mattermost for team chat?
Run Synapse only if you specifically want federation with other servers. If you want private team chat, it is the wrong shape of work: room state, not messages, dominates the database, and the project's own tracker has reports of state_groups_state reaching 274 million rows and 51 GB. Schedule synapse_auto_compressor from day one. Mattermost gives you Slack's shape on PostgreSQL 14 or newer, but from v11 Team Edition is capped at 250 activated users and lost GitLab SSO, so free now means local accounts.
Published . Last reviewed . Found something out of date? Tell us and we will fix it and log the change.