A modern, self-hosted webmail client for Stalwart Mail Server, built with Next.js and the JMAP protocol.
Bulwark is a full webmail suite – not just an inbox. It bundles the four apps most self-hosters end up wanting on the same login:
- Mail – threading, unified inbox, full-text search, Sieve filters, S/MIME, templates
- Calendar – month/week/day/agenda, recurring events, iMIP invitations, CalDAV subscriptions
- Contacts – multiple address books, groups, vCard import/export
- Files – Stalwart's JMAP FileNode storage with previews and folder upload
Plus the infrastructure around them: OAuth2 / OIDC SSO, TOTP 2FA, multi-account (up to 5 at once), 14 languages, PWA install, dark/light themes, a plugin system with an extension marketplace, and a Stalwart admin dashboard.
Full feature list: FEATURES.md.
docker run -d -p 3000:3000 \
-e JMAP_SERVER_URL=https://mail.example.com \
ghcr.io/bulwarkmail/webmail:latestOr with Docker Compose:
cp .env.example .env.local
# Edit .env.local – set JMAP_SERVER_URL
docker compose up -dgit clone https://github.com/bulwarkmail/webmail.git
cd webmail
npm install
cp .env.example .env.local
# Edit .env.local – set JMAP_SERVER_URL
npm run build && npm startnpm run dev # Dev server with a mock JMAP server
npm run typecheck
npm run lintAll variables are evaluated at runtime, so Docker deployments can be reconfigured without rebuilding. Edit .env.local:
# Required
JMAP_SERVER_URL=https://mail.example.com
# Optional
APP_NAME=My WebmailServer listen address
HOSTNAME=0.0.0.0 # Default; use "::" for IPv6
PORT=3000OAuth2 / OIDC
OAUTH_ENABLED=true
OAUTH_CLIENT_ID=webmail
OAUTH_CLIENT_SECRET= # optional, for confidential clients
OAUTH_CLIENT_SECRET_FILE= # path to a file containing the secret
OAUTH_ISSUER_URL= # optional, for external IdPsEndpoints are auto-discovered via .well-known/oauth-authorization-server or .well-known/openid-configuration.
Session & settings sync
SESSION_SECRET= # openssl rand -base64 32
SESSION_SECRET_FILE=/session-secret # path to a file containing the secret
SETTINGS_SYNC_ENABLED=true
SETTINGS_DATA_DIR=./data/settings # mount as a volume in DockerCredentials are encrypted with AES-256-GCM and stored in an httpOnly cookie (30-day expiry). Settings sync stores per-account preferences encrypted at rest and requires SESSION_SECRET.
Custom JMAP endpoint
ALLOW_CUSTOM_JMAP_ENDPOINT=trueShows a "JMAP Server" field on the login form. External servers must CORS-allow the webmail origin.
Branding & PWA
APP_NAME=My Webmail
APP_SHORT_NAME=Webmail
APP_DESCRIPTION=Your personal mail
FAVICON_URL=/branding/favicon.svg
PWA_ICON_URL=/branding/icon.svg # falls back to FAVICON_URL
PWA_THEME_COLOR=#3b82f6
PWA_BACKGROUND_COLOR=#ffffff
APP_LOGO_LIGHT_URL=/branding/logo-light.svg
APP_LOGO_DARK_URL=/branding/logo-dark.svg
LOGIN_LOGO_LIGHT_URL=/branding/login-light.svg
LOGIN_LOGO_DARK_URL=/branding/login-dark.svg
LOGIN_COMPANY_NAME=My Company
LOGIN_WEBSITE_URL=https://example.com
LOGIN_IMPRINT_URL=https://example.com/imprint
LOGIN_PRIVACY_POLICY_URL=https://example.com/privacyExtension directory
EXTENSION_DIRECTORY_URL=https://extensions.bulwarkmail.orgEnables the admin marketplace for browsing and installing plugins and themes.
Stalwart integration & logging
STALWART_FEATURES=true # password change, Sieve filters, etc.
LOG_FORMAT=text # "text" or "json"
LOG_LEVEL=info # error | warn | info | debug| Key | Action |
|---|---|
j / k |
Navigate between emails |
Enter / o |
Open email |
Esc |
Close / deselect |
c |
Compose |
r / R |
Reply / Reply all |
f |
Forward |
s |
Star |
e |
Archive |
# |
Delete |
/ |
Search |
? |
Show all shortcuts |
| Framework | Next.js 16 with App Router |
| Language | TypeScript |
| Styling | Tailwind CSS v4 |
| State | Zustand |
| Protocol | Custom JMAP client (RFC 8620) |
| i18n | next-intl |
| Icons | Lucide React |
Stalwart is a Rust mail server with native JMAP support – not IMAP/SMTP with JMAP bolted on. It handles JMAP, IMAP, SMTP, and ManageSieve in a single self-hosted binary with no third-party dependencies.
See CONTRIBUTING.md.
GNU AGPL v3. This repository preserves the original MIT attribution for the fork lineage in NOTICE.
Thanks to root-fr/jmap-webmail and @ma2t for the groundwork this project builds upon.




