Skip to content

maathimself/mailflow

MailFlow Logo

MailFlow

A self-hosted, unified webmail client. Connect multiple IMAP/SMTP accounts (Gmail, iCloud, Outlook, custom) and read them all in one clean interface.

Please open an issue here if you encounter a problem. See the Security Notes section before deploying.

Licensing

MailFlow is dual-licensed:

  • AGPL-3.0 — free for personal use, self-hosting, and open-source projects. If you modify and distribute or host MailFlow, you must publish your changes under the same license.
  • Commercial License — $500 per installation, one-time. For businesses or deployments where AGPL obligations cannot be met. Purchase here.

Personal self-hosting is free and always will be. This licensing model exists to protect the project from commercial exploitation while keeping MailFlow freely available to individuals and families.

If you contribute code, please read the Contributor License Agreement. By submitting a pull request you agree to its terms.

Features

  • Unified inbox — all accounts merged in one view, sorted by date
  • Multiple layouts — classic, compact, wide reader, vertical split, and more
  • Multiple themes — dark, light, and several color schemes
  • Multi-language UI — English, French, Spanish, and Italian
  • Full-text search — across all connected accounts simultaneously
  • Real-time notifications — WebSocket-powered new-mail toasts and web push (PWA/browser)
  • Reply / Forward / Compose — correct per-account SMTP routing
  • Folder navigation — expand any account to browse folders
  • Star, delete, mark read — synced back to IMAP
  • User management — admin panel, invite-only registration, invite emails
  • SSO / OIDC — single sign-on via any OpenID Connect provider
  • Microsoft 365 / OAuth2 — for work accounts that require modern auth

Screenshots

Default dark theme
Default dark theme
Light theme
Light theme
Catppuccin theme
Catppuccin theme
Gruvbox theme
Gruvbox theme
Compose window
Compose window
Collapsed sidebar
Collapsed sidebar
Account management
Account management
Folder navigation
Folder navigation
Layout options
Layout options
Appearance settings
Appearance settings

Installation

There are three ways to run MailFlow. The pre-built image method is recommended for most users.


Option A — Pre-built images (recommended)

No cloning or building required. Docker pulls the pre-built images directly from GHCR.

Prerequisites

  • A server with Docker and Docker Compose installed

1. Download the compose file and default config

curl -o docker-compose.yml https://raw.githubusercontent.com/maathimself/mailflow/main/docker-compose.ghcr.yml
curl -o .env               https://raw.githubusercontent.com/maathimself/mailflow/main/.env.example

2. Configure environment

Edit .env — the required fields are:

Variable Description
APP_URL Full URL, e.g. https://mail.example.com
SESSION_SECRET openssl rand -hex 32
DB_PASSWORD openssl rand -hex 16
ENCRYPTION_KEY openssl rand -hex 32

3. Start

docker compose up -d

MailFlow will be available on port 443 (HTTPS, self-signed certificate) and port 80 (HTTP).

Ports are configurable in .env:

Variable Default Description
APP_PORT 443 HTTPS port
APP_HTTP_PORT 80 HTTP port

Optional — automatic HTTPS via Let's Encrypt: set DOMAIN and ACME_EMAIL in .env, download the HTTPS overlay, then restart:

curl -o docker-compose.https.yml https://raw.githubusercontent.com/maathimself/mailflow/main/docker-compose.https.yml
docker compose -f docker-compose.yml -f docker-compose.https.yml --profile https up -d

This adds a Caddy reverse proxy that handles certificate issuance and renewal automatically. Requires Docker Compose 2.21+, a public domain with DNS pointing at the server, and ports 80/443 open.

Optional — behind your own reverse proxy: point your proxy at port 80. Set APP_HTTP_PORT in .env if you need a different host port. Your proxy should forward X-Forwarded-Proto: https so that session cookies are marked Secure correctly.

4. Create your admin account

Open https://your-domain.com in a browser. The first account registered becomes the admin. After registering, you can close registration and manage users from the settings panel → Users tab.

5. Add your email accounts

In the settings panel → Accounts → Add Account. Select a preset (Gmail, iCloud) or Custom for any IMAP server.

Updating

docker compose pull
docker compose up -d

To pin to a specific version instead of latest, add MAILFLOW_VERSION=1.0.0 to your .env.


Option B — Build from source

Prerequisites

  • A server with Docker and Docker Compose installed

1. Get the code

git clone https://github.com/maathimself/mailflow.git mailflow
cd mailflow

2. Configure environment

cp .env.example .env

Edit .env — the required fields are:

Variable Description
APP_URL Full URL, e.g. https://mail.example.com
SESSION_SECRET openssl rand -hex 32
DB_PASSWORD openssl rand -hex 16
ENCRYPTION_KEY openssl rand -hex 32

3. Build and start

docker compose up -d --build

First build takes 2–3 minutes. MailFlow will be available on port 443 (HTTPS, self-signed certificate) and port 80 (HTTP).

Optional — automatic HTTPS via Let's Encrypt: set DOMAIN and ACME_EMAIL in .env, then start with the HTTPS overlay (requires Docker Compose 2.21+):

docker compose -f docker-compose.yml -f docker-compose.https.yml --profile https up -d --build

Optional — behind your own reverse proxy: point your proxy at port 80. Your proxy should forward X-Forwarded-Proto: https so that session cookies are marked Secure correctly.

4. Create your admin account

Open https://your-domain.com in a browser. The first account registered becomes the admin. After registering, you can close registration and manage users from the settings panel → Users tab.

5. Add your email accounts

In the settings panel → Accounts → Add Account. Select a preset (Gmail, iCloud) or Custom for any IMAP server.


Option C — Native install (no Docker)

Run MailFlow directly on any Linux, macOS, or BSD machine using Node.js, PostgreSQL, and Redis. No container runtime required. The steps below use Ubuntu/Debian; adapt package manager commands for other platforms.

Prerequisites

  • Node.js 20+nodejs.org or via your package manager
  • PostgreSQL 16+
  • Redis 7+
  • nginx — serves the built frontend and proxies API/WebSocket requests to the backend

1. Install system dependencies

Ubuntu / Debian:

# Node.js 20 via NodeSource
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt-get install -y nodejs postgresql redis-server nginx

macOS (Homebrew):

brew install node@20 postgresql@16 redis nginx
brew services start postgresql@16
brew services start redis

2. Create the database

sudo -u postgres psql <<'SQL'
CREATE USER mailflow WITH PASSWORD 'replace-with-a-strong-password';
CREATE DATABASE mailflow OWNER mailflow;
SQL

3. Get the code

git clone https://github.com/maathimself/mailflow.git /opt/mailflow
cd /opt/mailflow

4. Configure environment

cp .env.example .env

Edit .env. In addition to the required secrets, set these for a native install:

Variable Value
APP_URL Full URL, e.g. https://mail.example.com
SESSION_SECRET openssl rand -hex 32
DB_HOST localhost
DB_NAME mailflow
DB_USER mailflow
DB_PASSWORD password you set in step 2
REDIS_URL redis://localhost:6379
ENCRYPTION_KEY openssl rand -hex 32

5. Build the frontend

cd /opt/mailflow/frontend
npm ci
npm run build
# Built files are written to /opt/mailflow/frontend/dist

6. Install backend dependencies

cd /opt/mailflow/backend
npm ci --omit=dev

7. Configure nginx

A ready-to-use nginx config is provided in contrib/nginx.conf. Copy it, update the root path, then enable it:

sudo mkdir -p /etc/nginx/sites-available /etc/nginx/sites-enabled
sudo cp /opt/mailflow/contrib/nginx.conf /etc/nginx/sites-available/mailflow

Open /etc/nginx/sites-available/mailflow and replace /path/to/mailflow/frontend/dist with /opt/mailflow/frontend/dist.

The provided config listens on port 80 for use behind a TLS-terminating reverse proxy (Nginx/Caddy/Traefik). If you want nginx to terminate TLS directly, uncomment the HTTPS server block in the file and set your certificate paths. A quick self-signed cert:

sudo mkdir -p /etc/ssl/mailflow
sudo openssl req -x509 -nodes -newkey rsa:4096 -days 3650 \
  -keyout /etc/ssl/mailflow/key.pem \
  -out    /etc/ssl/mailflow/cert.pem \
  -subj "/CN=mailflow"

Enable the site and reload nginx:

sudo ln -sf /etc/nginx/sites-available/mailflow /etc/nginx/sites-enabled/mailflow
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t && sudo systemctl reload nginx

8. Run the backend

Option A — systemd (recommended for production):

sudo cp /opt/mailflow/contrib/mailflow.service /etc/systemd/system/mailflow.service
# Edit the service file if your install path or user differs from the defaults
sudo systemctl daemon-reload
sudo systemctl enable --now mailflow
sudo systemctl status mailflow

Option B — PM2:

sudo npm install -g pm2
cd /opt/mailflow/backend
pm2 start src/index.js --name mailflow
pm2 save
pm2 startup   # follow the printed command to register auto-start on boot

Option C — foreground (testing only):

cd /opt/mailflow/backend
node src/index.js

9. Create your admin account

Open the app in a browser. The first account registered becomes the admin. After registering, close open registration from Settings → Users.

10. Add your email accounts

In the settings panel → Accounts → Add Account.

Updating

cd /opt/mailflow
git pull
cd frontend && npm ci && npm run build && cd ..
cd backend && npm ci --omit=dev && cd ..
sudo systemctl restart mailflow   # or: pm2 restart mailflow

Email Provider Setup

Gmail

Gmail requires an App Password (not your normal password):

  1. Enable 2-step verification on your Google account
  2. Go to myaccount.google.com/apppasswords
  3. Create a new App Password — name it "MailFlow"
  4. Use the 16-character password in the MailFlow account form
Setting Value
IMAP Host imap.gmail.com
IMAP Port 993
SMTP Host smtp.gmail.com
SMTP Port 587
Username your Gmail address

iCloud / Apple Mail

  1. Go to appleid.apple.com → Sign-In and Security → App-Specific Passwords
  2. Generate a password — name it "MailFlow"
Setting Value
IMAP Host imap.mail.me.com
IMAP Port 993
SMTP Host smtp.mail.me.com
SMTP Port 587
Username your full iCloud email (you@icloud.com)

Microsoft 365 / Outlook (OAuth2)

Work/school accounts that require modern authentication:

  1. In MailFlow settings → Integrations → Microsoft 365 — follow the Azure App Registration instructions shown there
  2. After saving the config, click Connect Microsoft account

Custom IMAP

Any standard IMAP/SMTP server works. Use port 993 for IMAP (TLS) and 587 (STARTTLS) or 465 (TLS) for SMTP.


Management

# View all logs
docker compose logs -f

# View backend logs only
docker compose logs -f backend

# Stop
docker compose down

# Stop and delete all data (destructive)
docker compose down -v

# Update to latest images (pre-built install)
docker compose pull && docker compose up -d

# Rebuild after a code change (Docker build-from-source install)
docker compose up -d --build

# Update a native install
git pull && \
  cd frontend && npm ci && npm run build && cd .. && \
  cd backend && npm ci --omit=dev && cd .. && \
  sudo systemctl restart mailflow   # or: pm2 restart mailflow

Backup and Restore

# Backup database
docker exec mailflow-postgres pg_dump -U mailflow mailflow \
  > mailflow-$(date +%Y%m%d).sql

# Restore database
cat mailflow-YYYYMMDD.sql | \
  docker exec -i mailflow-postgres psql -U mailflow -d mailflow

Architecture

Default deployment (self-signed HTTPS)

Browser (HTTPS / HTTP)
  │
  ▼
nginx  (frontend container — ports 443 + 80)
  │
  ├── /api/*  → Node.js backend (port 3000)
  ├── /oauth/ → Node.js backend (port 3000)
  └── /ws     → Node.js backend WebSocket (port 3000)
                    │
                    ├── PostgreSQL  (messages, accounts, users)
                    ├── Redis       (sessions)
                    └── IMAP        (outbound to mail servers)

nginx and the backend communicate on an internal Docker network. PostgreSQL and Redis are not exposed outside that network.

With your own reverse proxy

Browser (HTTPS)
  │
  ▼
Your proxy  (Nginx / Traefik / Caddy / etc. — TLS termination)
  │  X-Forwarded-Proto: https
  ▼
nginx  (frontend container — port 80)
  │
  └── backend, PostgreSQL, Redis (internal network, unchanged)

With automatic HTTPS (--profile https)

Browser (HTTPS)
  │
  ▼
Caddy  (ports 80/443 — TLS termination, auto Let's Encrypt)
  │
  ▼
nginx  (frontend container — internal only)
  │
  └── backend, PostgreSQL, Redis (internal network, unchanged)

Star History

Star History Chart


Security notes

  • The first registered user becomes the admin automatically
  • Close open registration in Settings → Users once you've set up your accounts
  • Use the invite system to onboard additional users
  • Enable two-factor authentication (TOTP) in Settings → Security for extra account protection
  • Session cookies are HttpOnly, SameSite=Lax, with a 7-day TTL. The Secure flag is set automatically when the connection is HTTPS (direct or via a proxy that forwards X-Forwarded-Proto: https)
  • Passwords are bcrypt-hashed (cost factor 12)
  • Login and registration endpoints are rate-limited (10 attempts per 15 minutes per IP)
  • Database and Redis are not exposed outside the Docker network
  • IMAP/SMTP credentials are stored at rest in the database (standard for webmail clients — protect access to your server and database volume accordingly)

About

A self-hosted, unified webmail client.

Topics

Resources

License

AGPL-3.0, Unknown licenses found

Licenses found

AGPL-3.0
LICENSE
Unknown
LICENSE-COMMERCIAL

Contributing

Stars

Watchers

Forks

Sponsor this project

 

Contributors

Languages