SkimMail

English · Tiếng Việt · 中文

Skim all your inboxes. A lightweight, self-hosted, read-first multi-account email reader — IMAP core + Gmail/Outlook OAuth — packaged as a single Go binary that embeds a React SPA. No external services required.

License: Business Source License 1.1 (proprietary; converts to AGPL in 2030) · Security: SECURITY.md · Docs: Wiki

Everything below is shipped. Multi-account mail, per-account egress, rules and alerts, notifications, backup & restore, plugins, remote access and multi-user roles are all in the current release — AI Triage is the only headline feature still on the roadmap. Release-by-release detail: CHANGELOG.md.

SkimMail: five accounts in three groups down the left, a unified inbox in the middle with per-bundle counts and colour-coded tags, and an opened message with its attachment on the right.


Features

Read

Give every account its own way out

Automate and operate

Security & multi-user

Requirements

Just Docker — SQLite is built in, no external services needed. (Building from source or contributing? See README.dev.md.)


Quick start

No source needed — grab the published compose file (it pulls the prebuilt image):

curl -fsSLO https://lyquyduong.github.io/skimmail/docker-compose.yml
docker compose up -d      # → http://localhost:8080  (SQLite + filesystem)

Or run the published image directly (distroless + non-root; data in the /data volume):

docker run -d --name skimmail -p 8080:8080 -v skimmail-data:/data \
  -e AUTH_MODE=passphrase ghcr.io/lyquyduong/skimmail:latest

One image, one package. Embedded WireGuard egress, PostgreSQL, MySQL and S3 support are all in the default build — the WireGuard engine arrives as a SHA256-pinned plugin SkimMail downloads the first time you add a tunnel, so there is nothing extra to install and no second image to choose. The separate skimmail-wg edition was retired in 1.7.0; if you still have that apt package, apt remove skimmail-wg is safe.

Install on Ubuntu / Debian (apt)

curl -fsSL https://lyquyduong.github.io/skimmail/apt/skimmail.gpg \
  | sudo tee /usr/share/keyrings/skimmail.gpg >/dev/null
echo "deb [signed-by=/usr/share/keyrings/skimmail.gpg] https://lyquyduong.github.io/skimmail/apt stable main" \
  | sudo tee /etc/apt/sources.list.d/skimmail.list
sudo apt update && sudo apt install skimmail      # runs as a systemd service → http://localhost:8080

Config lives in /etc/default/skimmail; data in /var/lib/skimmail; logs go to the systemd journal (sudo journalctl -u skimmail -f) and a rotating file at /var/log/skimmail/skimmail.log — level, rotation, truncate, and a realtime viewer live in Settings ▸ Logs. Upgrades come via apt upgrade. All release channels (image, .deb, apt repo) ship from GitHub — see DISTRIBUTION.md.

First login

Open http://localhost:8080. Before it lets you create anything, SkimMail asks for a one-time claim code it printed at first boot — it is what stops whoever reaches the port first from claiming your instance:

sudo journalctl -u skimmail | grep 'claim code'        # apt (sudo: the journal is root-only)
docker compose logs skimmail | grep 'claim code'       # docker compose (service name; the container is skimmail-skimmail-1)
docker logs skimmail 2>&1 | grep 'claim code'          # docker run (only if you passed --name skimmail, as above)

Lost it? Mint a replacement — the old one stops working:

sudo -u skimmail skimmail --data-dir /var/lib/skimmail claim-code --rotate

On a closed network you can skip the gate entirely with SKIMMAIL_SKIP_CLAIM=1.

Then the default auth mode is passphrase: the first password you enter becomes your master passphrase — remember it (it's used to log in again). Leave the username blank.

Add a mail account

Add an IMAP account: email · host (e.g. imap.gmail.com) · port 993 · security TLS · app password.

Gmail takes an app-specific password (not your normal password) — two clicks, no Cloud project. Outlook.com and Hotmail cannot: Microsoft issues no app passwords for personal accounts and has switched basic authentication off, so those mailboxes need OAuth.

To enable the "Add with Google/Microsoft" buttons, set the OAuth credentials below. A public BASE_URL is not required — an instance without one finishes the sign-in by pasting the address the browser lands on.

Press ↻ Sync (or wait for the background poll). New mail then pushes in real-time over WebSocket.


Usage


Configuration

Config is via environment variables (12-factor) — see .env.example. Since 1.9.0 most settings are also editable in the app (Settings), and a value set in the environment always wins and shows there as locked. The full reference — every variable, the config planes, and what overrides what — is in the wiki ▸ Configuration.

Variable Default Purpose
AUTH_MODE passphrase passphrase (one shared passphrase) or users (named accounts with roles). Since 1.10.0 users is really multi-user: each account owns its own mailboxes and cannot see anyone else's, and each user is owner, operator or viewer. Create them with skimmail user add. A third value, none, turns authentication off entirely; it additionally requires SKIMMAIL_ALLOW_AUTH_NONE=1 in the process environment, because auth.mode is writable from the UI and the CLI and a stolen session must not be able to downgrade the instance on its own.
DATA_DIR ./data SQLite DB, master key, blobs
LISTEN_ADDR :8080 listen address
BASE_URL public URL — needed for the OAuth redirect flow, WebSocket and PWA. OAuth still works without it via the paste flow.
TRUST_PROXY false trust X-Forwarded-* behind a reverse proxy
TRUSTED_PROXIES comma-separated CIDRs trusted as proxy hops when TRUST_PROXY=true (default: loopback/private only)
TRUSTED_ORIGINS extra CORS/CSRF-allowed origins (comma-separated)
BACKGROUND_POLL_INTERVAL 5m poll-fallback period for every account
MAX_CONCURRENT_SYNCS 4 max mailboxes syncing at once
SYNC_RATE_PER_MIN 10 max sync starts per minute (stagger)
SYNC_DEPTH_DAYS 30 header sync window (0 = full history)
GOOGLE_CLIENT_ID / _SECRET Gmail OAuth app (optional)
MICROSOFT_CLIENT_ID / _SECRET Outlook OAuth app (optional)

Security

Credentials, OAuth tokens and cached message bodies are encrypted at rest (AES-256-GCM). The first sign-in is gated by a one-time claim code. The server applies login rate-limiting + lockout, CSRF/origin checks, an SSRF guard on outbound fetches, strict security headers + a sandboxed email iframe, a server-enforced idle lock, and an append-only audit log (GET /api/audit). See SECURITY.md for the full posture and how to report a vulnerability.

Uninstall (complete removal)

Uninstalling never deletes your data by itself — accounts, the mail cache, and the encryption master key live in the Docker volume or /var/lib/skimmail. The steps marked ⚠ below delete them permanently (there is no way back without a backup).

Docker Compose

docker compose down -v            # ⚠ stops + removes containers AND the data volumes
docker rmi ghcr.io/lyquyduong/skimmail:latest 2>/dev/null
rm docker-compose.yml             # the file you downloaded

Docker (docker run)

docker rm -f skimmail
docker volume rm skimmail-data    # ⚠ all data
docker rmi ghcr.io/lyquyduong/skimmail:latest

APT (Ubuntu / Debian)

sudo apt purge skimmail           # stops the service, removes the binary, the
                                  # systemd unit and /etc/default/skimmail
sudo rm -rf /var/lib/skimmail     # ⚠ data — apt keeps it on purpose
sudo rm -rf /var/log/skimmail     # log file + rotated backups
sudo userdel skimmail             # the system user created at install
# remove the APT repo + signing key you added:
sudo rm -f /etc/apt/sources.list.d/skimmail.list /usr/share/keyrings/skimmail.gpg
sudo apt update

Manual binary (tarball) — stop the process (or your own systemd unit), then delete the binary and its data dir (DATA_DIR, default ./data next to the binary).

Developers

Building from source, dev mode (hot reload), VS Code setup, build tags, tests, and project layout are in README.dev.md.

License & Tiers

SkimMail is proprietary software. It is licensed under the Business Source License 1.1 (Licensor: Solutions101 (S101)). The source code is private; only compiled binaries are distributed to users. SPDX: BUSL-1.1.

Three Tiers

See COMMERCIAL-TERMS.md for details, or the full explainer (EN + VI) in docs/LICENSING.md. Questions about licensing: see SECURITY.md.

License Conversion (2030)

After July 23, 2030, SkimMail will automatically convert to AGPL-3.0-or-later. Until then, source code remains proprietary.

Other Notices