Fix the tag prefix format for SHA in Docker publish workflow.
Bulwark Webmail
A modern, self-hosted webmail client for Stalwart Mail Server.
Built with Next.js and the JMAP protocol.
Screenshots
More screenshots
Light mode — Full theme support with intelligent color transformation |
Settings — Appearance, identities, filters, templates, and more |
Login — Configurable branding with OAuth2/OIDC and 2FA support |
Features
- Read, compose, reply, reply-all, forward with rich HTML rendering
- Threading — Gmail-style inline expansion with thread navigation
- Draft auto-save with discard confirmation
- Attachments — upload, download, and inline preview
- Search — full-text with JMAP filter panel, search chips, cross-mailbox queries, wildcard support, and OR conditions
- Batch operations — multi-select with checkboxes, archive, delete, move, tag
- Archive modes — archive directly or organize archived mail by year or month
- Print emails directly from the viewer
- Color tags/labels and star/unstar
- Virtual scrolling for large mailboxes
- Quick reply from the viewer
- Sender avatars — favicon-based with negative caching for performance
- Recipient popover for quick contact interaction
- TNEF support — extract Outlook
winmail.datmessage bodies and attachments automatically - Folder management — create, rename, delete folders with icon picker and subfolder support
- Tag counts — unread and total counts displayed in sidebar
Calendar
- Month, week, day, and agenda views with mini-calendar sidebar
- Event hover preview popover with details
- Drag-and-drop rescheduling, click-drag creation, edge-resize (15-min snap)
- Recurring events with edit/delete scope (this / this and following / all)
- Participant scheduling — iTIP invitations, organizer/attendee UI, RSVP
- Inline calendar invitations in email viewer — auto-detect
.ics, RSVP, import - iCalendar import with preview and bulk create
- Notifications with configurable sound and alert persistence
- Real-time sync via JMAP push
Contacts
- Contact management with JMAP sync (RFC 9553/9610) and local fallback
- Contact groups with group expansion and member management
- vCard import/export (RFC 6350) with duplicate detection
- Autocomplete in composer (To/Cc/Bcc)
- Bulk operations — multi-select, delete, group add, export
Filters & Automation
- Server-side email filters via JMAP Sieve Scripts (RFC 9661)
- Visual rule builder — conditions (From, To, Subject, Size, Body…) and actions (Move, Forward, Star, Discard…)
- Raw Sieve editor with syntax validation
- Vacation responder with date range scheduling and sidebar indicator
- Email templates — reusable, categorized, with placeholder auto-fill (
{{recipientName}},{{date}}, etc.)
Files
- File browser with JMAP FileNode cloud storage (Stalwart native)
- Upload and download files with progress tracking and folder upload support
- Folder navigation with breadcrumb path and tree sidebar
- Grid and list views with sorting by name, size, or date
- Clipboard operations — cut, copy, paste, duplicate files
- File preview for images, text, audio, video, and more
- Favorites and recent files for quick access
- Bulk operations — multi-select, delete, move, download
Security & Privacy
- External content blocked by default — trusted senders list for auto-load
- HTML sanitization via DOMPurify with XSS prevention
- S/MIME — manage certificates, sign outgoing mail, encrypt to recipients, decrypt messages, and verify signatures
- SPF/DKIM/DMARC status indicators
- OAuth2/OIDC with PKCE for SSO (Keycloak, Authentik, or built-in), with OAuth-only mode
- TOTP two-factor authentication
- Account security panel — manage passwords and 2FA via Stalwart admin API
- "Remember me" — AES-256-GCM encrypted httpOnly cookie (opt-in)
- Security headers — CSP with per-request nonce, X-Frame-Options, Referrer-Policy
- Newsletter unsubscribe (RFC 2369)
Interface
- Three-pane layout — sidebar, email list, viewer with resizable columns
- Dark and light themes with intelligent email color transformation
- Always-light email rendering option for problematic HTML messages in dark theme
- Responsive — desktop sidebar + mobile bottom tab bar with tablet support
- Keyboard shortcuts — full navigation without a mouse
- Drag-and-drop email organization between mailboxes and tag assignment
- Right-click context menus, toast notifications with undo, form validation with shake feedback
- Customizable toolbar position, custom favicon, sidebar/login logos, and login page branding
- Sidebar apps — pin custom tools to the navigation rail and open them inline or in a new tab
- Settings sync — preferences synchronized with the server (encrypted)
- Storage quota display
- Shared folders — multi-account access
- Accessibility — WCAG AA contrast, reduced-motion support, focus trap, screen reader live regions
Internationalization
8 languages: English · Français · 日本語 · Español · Italiano · Deutsch · Nederlands · Português
Automatic browser detection with persistent preference.
Identity Management
- Multiple sender identities with per-identity signatures
- Identity refresh — keep the identity manager aligned with server-side changes after edits
- Sub-addressing —
user+tag@domain.comwith contextual tag suggestions - Identity badges in viewer and email list
Operations
- Automatic update check — server logs when a newer release is available
Quick Start
Docker (recommended)
docker run -d -p 3000:3000 \
-e JMAP_SERVER_URL=https://mail.example.com \
ghcr.io/bulwarkmail/webmail:latest
Or with Docker Compose:
cp .env.example .env.local
# Edit .env.local — set JMAP_SERVER_URL
docker compose up -d
From Source
git 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 start
Development
npm run dev # Start dev server (mock JMAP server included)
npm run typecheck # Type checking
npm run lint # Linting
Configuration
Edit .env.local:
# Required
JMAP_SERVER_URL=https://mail.example.com
# Optional
APP_NAME=My Webmail
All variables are runtime — Docker deployments can be configured without rebuilding.
Server Listen Address
HOSTNAME=0.0.0.0 # Default; use "::" for IPv6
PORT=3000 # Default listen port
OAuth2/OIDC (SSO)
OAUTH_ENABLED=true
OAUTH_CLIENT_ID=webmail
OAUTH_CLIENT_SECRET= # optional, for confidential clients
OAUTH_ISSUER_URL= # optional, for external IdPs (Keycloak, Authentik)
Endpoints are auto-discovered via .well-known/oauth-authorization-server or .well-known/openid-configuration.
Remember Me
SESSION_SECRET=your-secret-key # Generate with: openssl rand -base64 32
Credentials encrypted with AES-256-GCM, stored in an httpOnly cookie (30-day expiry).
Keyboard Shortcuts
| 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 |
Tech Stack
| 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 |
Why Stalwart?
Stalwart is a mail server written in Rust with native JMAP support — not IMAP/SMTP with JMAP bolted on. It handles JMAP, IMAP, SMTP, and ManageSieve in a single binary. Self-hosted, no third-party dependencies.
Contributing
See CONTRIBUTING.md for guidelines.
Roadmap
See ROADMAP.md for planned features and current status.
License
This repository also preserves the original MIT attribution notice for the fork lineage in NOTICE.
Acknowledgments
Thanks to root-fr/jmap-webmail and @ma2t for doing most of the groundwork that this project builds upon.






