MailFlow comes in two flavors: the Desktop Suite (five native apps for Windows, Mac and Linux β free for personal use) and a self-hosted web edition (multi-user server for your team). Both connect to the mail server you already have β nothing about your existing email setup changes.
One download gives you five native apps β MailFlow (email), CalendarFlow, NoteFlow, ContactFlow, and ChatFlow β with per-app taskbar/Dock icons, unread badges, desktop notifications, and one sign-in shared across all of them.
One file per platform installs the whole suite:
MailFlow-Suite-Setup-1.5.0-Windows.exe. It's a per-user install (no admin rights needed) β the apps land in %LOCALAPPDATA%\MailFlowSuite with Start-menu shortcuts under MailFlow Suite. The installer asks which app shortcuts to create β all five apps are always installed, because each app's switcher menu can launch its siblings. Optionally let it make MailFlow the default handler for mailto: links. First launch: Windows SmartScreen may show "Windows protected your PC" because the apps aren't code-signed. Click More info β Run anyway. This only happens once per app.MailFlow-Suite-1.5.0-Android.apk and open it (allow "install unknown apps" for your browser if asked β it is not from the Play Store). The app signs in against your MailFlow server account; notifications arrive natively once permission is granted on first launch.MailFlow-Suite-1.5.0-macOS.dmg and drag the apps (or the whole window's contents) into Applications. All five apps work side by side; the app-switcher menu in any of them launches (or focuses) its siblings.MailFlow-Suite-1.5.0-Linux-x86_64.tar.gz and run ./install.sh from the extracted folder. It's a per-user install (no root): the five apps land in ~/.local/share/mailflow-suite with menu entries and icons. You can also run the apps straight from the extracted folder. The app-switcher menu in any of them launches (or focuses) its siblings.sudo apt install libwebkit2gtk-4.1-0 libgtk-3-0 (Debian/Ubuntu) or sudo dnf install webkit2gtk4.1 gtk3 (Fedora). Data lives in ~/.config/MailFlowSuite/ (shared sign-in) and ~/.config/MailFlow/ (per-app logs); delete both to reset. Updating = download the new tar.gz and re-run install.sh β data and sign-in are untouched.
xattr -dr com.apple.quarantine /Applications/MailFlow.app in Terminal for each app. One-time per app; it launches normally afterwards.
The first time you open any suite app it asks how you'll use it:
https://mail.yourcompany.com) and sign in once with your email address and mail password. Every suite app shares that sign-in: open CalendarFlow or ChatFlow next and you're already logged in.| Field | Typical value | Notes |
|---|---|---|
| IMAP server | mail.example.com | Receives mail. Usually your mail host or imap.your-domain |
| IMAP port | 993 + TLS | 993 = implicit TLS (recommended). Use 143 with TLS off only on trusted LANs. |
| SMTP server | mail.example.com | Sends mail. Usually your mail host or smtp.your-domain |
| SMTP port | 587 + TLS | 587 = STARTTLS (most common). Port 465 also supported (implicit TLS). |
MailFlow authenticates directly against your IMAP server β there is no separate MailFlow account to create and your password never leaves your machine (it's stored encrypted locally).
imap.gmail.com:993 and smtp.gmail.com:587 with the app password.
The same app-password pattern applies to any provider that doesn't accept plain passwords over IMAP.
Your first sign-in starts the initial sync β existing folders and message history are pulled in, then kept current with IMAP IDLE push. New mail shows a desktop notification and the MailFlow taskbar badge counts unread.
| Platform | Data directory |
|---|---|
| Windows | C:\Users\you\AppData\Local\MailFlowSuite\ and C:\Users\you\AppData\Roaming\MailFlow\ |
| macOS | ~/Library/Application Support/MailFlowSuite/ (suite config & shared sign-in) and ~/Library/Application Support/MailFlow/ (local database, attachments, per-app logs) |
| Linux | ~/.config/MailFlowSuite/ (suite config & shared sign-in) and ~/.config/MailFlow/ (local database, attachments, per-app logs) |
The first holds the suite's apps and shared settings; the second holds your local database, attachments, and per-app logs. Updating on Windows = run the new installer β your data and sign-in are untouched (or just click Install when the in-app update banner appears). Updating on macOS = download the new DMG and drag over the old apps β data and sign-in are untouched. Updating on Linux = download the new tar.gz and re-run install.sh β data and sign-in are untouched. Uninstalling = Windows Settings β Apps β MailFlow Desktop Suite, on macOS drag the apps to the Trash, or on Linux remove ~/.local/share/mailflow-suite and the mailflow-suite-* menu entries (data folders remain until you delete them).
The full multi-user deployment: one Go binary and a web-based setup wizard. Point it at your MariaDB or use the built-in SQLite, connect your existing IMAP/SMTP server, paste your license key β done. Serves your team at https://mail.yourcompany.com.
The server is a single static binary. Run it from its own directory:
[Unit] Description=MailFlow After=network.target [Service] WorkingDirectory=/opt/mailflow ExecStart=/opt/mailflow/mailflow-go Restart=on-failure User=mailflow [Install] WantedBy=multi-user.target
sudo systemctl daemon-reload sudo systemctl enable --now mailflow
On first boot (no configuration present) MailFlow serves a setup wizard at http://your-server:5174/ instead of the app. It walks you through:
setup.json, runs the database migrations with a progress bar, and tells you when to restart the service.After the restart the app is live: browse to it and sign in with your own email address and mail password β MailFlow validates credentials against your IMAP server. The first account to sign in automatically becomes the admin. Teammates simply sign in with their mailbox credentials; accounts are provisioned on first login (up to your tier's user limit).
All the wizard settings can still be provided (or overridden) the classic way via a .env file β see the environment reference below. The wizard's setup.json takes precedence over .env for the sections it defines.
Built-in (recommended): MailFlow embeds Caddy's TLS engine. Add one line to .env (or fill the HTTPS box in the wizard) and it obtains and renews Let's Encrypt certificates itself β no proxy, no certbot, no cron:
AUTO_TLS_DOMAINS=mail.example.com # your DNS name, pointed at this server # AUTO_TLS_EMAIL=you@example.com # optional ACME contact # DISABLE_HTTP=true # optional: turn off the plain-HTTP port
MailFlow then serves https:// on port 443 directly (HTTP/2 included) and redirects port 80 to it. Your DNS record must point at the server and ports 80/443 must be reachable from the internet β validation happens over HTTP-01/TLS-ALPN-01, no DNS provider setup needed.
Own proxy instead? Fine β just don't set AUTO_TLS_DOMAINS. MailFlow stays plain HTTP on its port and you terminate TLS wherever you like:
mail.example.com {
reverse_proxy 127.0.0.1:5174
}
nginx works too (proxy_pass to 127.0.0.1:5174; leave buffering on). HTTPS isn't optional in practice β browsers only allow passkey registration on secure origins.
https://mail.example.com and sign in with your own email address and mail password β MailFlow validates credentials against your IMAP server.Every wizard setting has an environment-variable equivalent in .env (next to the binary, same directory you run it from) and a command-line flag (mailflow-go --port=8080 β run --help for the list). setup.json β written by the wizard β takes precedence over .env for the sections it defines; command-line flags override everything.
| Variable | Default | What it does |
|---|---|---|
LICENSE_KEY | β | Required. Your MF1.β¦ license key. Verified at startup; invalid keys refuse to boot. |
PORT | 5174 | Plain-HTTP listen port. Change it if 5174 is taken or you proxy to a different loopback port. |
ORIGIN | http://localhost:5174 | Public HTTPS origin β must match exactly for passkey login. |
DB_HOST DB_PORT DB_NAME DB_USER DB_PASS | see .env.example | MariaDB/MySQL connection. DB_NAME=sqlite switches to the built-in SQLite backend (SQLITE_PATH picks the file). |
IMAP_HOST IMAP_PORT IMAP_TLS | localhost 993 true | Your IMAP server β users authenticate against it. |
SMTP_HOST SMTP_PORT SMTP_TLS | localhost 587 true | Your SMTP server for sending. |
JWT_SECRET | β | Session key; also derives the encryption key for stored IMAP passwords. Random 32-byte hex (openssl rand -hex 32). The wizard generates one. |
ATTACHMENT_DIR | ./attachments | Attachment storage (shared volume in cluster mode). |
AUTO_TLS_DOMAINS | unset | Enables built-in Let's Encrypt HTTPS on :443 (see Step 3). Unset = plain HTTP on PORT for your own proxy. |
CLUSTER_ROLE CLUSTER_SHARD_INDEX CLUSTER_SHARD_COUNT | all 0 1 | Cluster mode: run several nodes on one shared MariaDB. web = UI only, worker = mail sync for its shard of users, all = single server. |
ATTACHMENT_DIR folder.setup.json (written by the wizard) or LICENSE_KEY in .env. The admin panel (Settings β Admin β License) shows the current license and lets an admin apply a new key live β e.g. to upgrade tiers without reinstalling.