A self-hosted, multi-user, encrypted web email client written entirely in Go. Supports Gmail and Outlook via OAuth2, plus any standard IMAP/SMTP provider (Fastmail, ProtonMail Bridge, iCloud, etc.).
- **Per-user IP rules** — three modes: `disabled` (global rules apply), `brute_skip` (listed IPs bypass lockout counter), `allow_only` (only listed IPs may log in to this account)
All commands open the database directly without starting the HTTP server. They require the same environment variables or `data/gowebmail.conf` as the server.
> **Note:** `--list-admin`, `--pw`, and `--mfa-off` only work on admin accounts. Regular user management is done through the web UI at `/admin`. `--blocklist` and `--unblock` are particularly useful if you have locked yourself out.
---
## Configuration
On first run, `data/gowebmail.conf` is auto-generated with all defaults and inline comments. All keys can also be set via environment variables. The Admin → Settings UI can edit and save most values at runtime, writing changes back to `gowebmail.conf`.
### Core
| Key | Default | Description |
|-----|---------|-------------|
| `HOSTNAME` | `localhost` | Public hostname for BaseURL construction and Host header validation |
| `LISTEN_ADDR` | `:8080` | Bind address |
| `SECURE_COOKIE` | `false` | Set `true` when running behind HTTPS |
| `TRUSTED_PROXIES` | _(blank)_ | Comma-separated IPs/CIDRs allowed to set `X-Forwarded-For` |
| `ENCRYPTION_KEY` | _(auto-generated)_ | AES-256 key — **back this up immediately**; losing it makes the DB unreadable |
| `BRUTE_ENABLED` | `true` | Enable automatic IP blocking on failed logins |
| `BRUTE_MAX_ATTEMPTS` | `5` | Failed login attempts before ban triggers |
| `BRUTE_WINDOW_MINUTES` | `30` | Rolling window in minutes for counting failures |
| `BRUTE_BAN_HOURS` | `12` | Ban duration in hours; `0` = permanent block (manual unblock required) |
| `BRUTE_WHITELIST_IPS` | _(blank)_ | Comma-separated IPs never blocked — **add your own IP here** |
### Geo Blocking
| Key | Default | Description |
|-----|---------|-------------|
| `GEO_BLOCK_COUNTRIES` | _(blank)_ | ISO country codes to deny outright (e.g. `CN,RU,KP`). Evaluated first — takes priority over allow list. |
| `GEO_ALLOW_COUNTRIES` | _(blank)_ | ISO country codes to allow exclusively (e.g. `SK,CZ,DE`). All other countries are denied. |
Geo lookups use [ip-api.com](http://ip-api.com) (free tier, no API key, ~45 req/min limit). Results are cached in-memory for 24 hours. Private/loopback IPs always bypass geo checks.
### Security Notification Emails
| Key | Default | Description |
|-----|---------|-------------|
| `NOTIFY_ENABLED` | `true` | Send alert email to user when a brute-force attack targets their account |
- **`ENCRYPTION_KEY` is critical** — back it up. Without it the encrypted SQLite database is permanently unreadable.
- Email content (subject, from, to, body), IMAP/SMTP credentials, and OAuth tokens are all encrypted at rest with AES-256-GCM at the field level.
- GoWebMail user passwords are bcrypt hashed (cost=12). Session tokens are 32-byte `crypto/rand` hex strings.
- All HTTP responses include security headers (CSP, X-Frame-Options, Referrer-Policy, etc.).
- HTML emails render in a CSP-sandboxed `<iframe>` — external links trigger a confirmation dialog before opening in a new tab.
- In production, run behind a reverse proxy with HTTPS (nginx / Caddy) and set `SECURE_COOKIE=true`.
- Add your own IP to `BRUTE_WHITELIST_IPS` to avoid ever locking yourself out. If it does happen, use `./gowebmail --unblock <ip>` — no server restart needed.