Rewrite mail CSS in place instead of cutting pieces out, so a strip can no longer join text into a closing </style>, and escape < last. Decode escaped letters before checking, parse url() properly and drop CSS that cannot be parsed, and disable @import and image-set() in every spelling. The body element's style goes through the same path. Give <area> links the same target, rel and click handling as <a>, strip <style> blocks from HTML quoted into the composer, and contain the editor's layout as .message-body already is.
Try the demo
A working copy with an invented mailbox behind it — no sign-up, nothing real, nothing kept.
ihasmail
Immutable webmail for Stalwart Mail Server. Mail, calendars, contacts, files and filters in one app that works as well on a phone as on a desktop — and a container with nothing to persist.
ihasmail talks only JMAP to Stalwart. There is no database, no IMAP or SMTP,
and with IMMUTABLE=1 no writable filesystem either: everything durable,
settings included, belongs to Stalwart, so the container is disposable.
| 🌐 ihasmail.org | What it is, what it looks like, the full feature list |
| 📘 docs.ihasmail.org | Installing · Configuring · Using it · Shortcuts · Rebranding · Troubleshooting |
| 📋 FEATURES.md | Everything it does, feature by feature, with the capability each one needs |
| 🧪 KNOWN-ISSUES.md | What was verified live, and where Stalwart departs from a spec |
| 🛣 ROADMAP.md | What ihasmail does not do, and why |
Screenshots
Inbox & conversation (dark) ![]() |
Inbox & conversation (light) ![]() |
Composer ![]() |
Calendar ![]() |
Contacts ![]() |
Sieve filter builder ![]() |
Taken against the built-in mock with sample data. More, including the phone layout, on ihasmail.org.
What's in it
- Mail — conversations, labels, search operators, keyboard shortcuts, scheduled and undo send, invitations and RSVP, filters made from a message
- Calendar — month, week, day and agenda views, recurrence, attendees and free-busy
- Contacts — address books, groups, vCard import and export
- Files — browse, upload, move, share
- Signature checking — S/MIME signed mail verified as you read it
- Settings that follow the account, kept in the account's own storage on Stalwart
- On a phone — swipe to archive or delete, pull to refresh, hold to select
- Administration — a dashboard, accounts, groups, mailing lists, roles, tenants and domains, each shown only when the Stalwart role allows it
- Ten interface languages and twelve themes — the nine translations are marked Beta until a native speaker has read them
- Platform — installable PWA, Web Push,
mailto:handler, no credentials in the browser, strict CSP
The long version is FEATURES.md and ihasmail.org.
Requirements
Stalwart 0.16 or newer — sign-in refuses anything older, by name. Tested against 0.16.22; what changed in each release is in KNOWN-ISSUES.md.
- No Stalwart yet? ihasmail-oneshot deploys a new Stalwart and ihasmail together on one host, in one command.
- On Stalwart 0.15? stalwart-migrator upgrades it in place, or stay on the
stalwart-0.15-supportrelease.
Quick start (Docker)
cp .env.example .env
# edit: STALWART_URL=https://mail.example.com and APP_SECRET=$(openssl rand -base64 48)
docker compose up --build -d
# → http://localhost:8080 — put a reverse proxy in front for TLS
Or pull the published image, ghcr.io/coffey-labs/ihasmail. Releases are
weekly, so it is usually a few days behind main.
People sign in with their Stalwart mailbox credentials. An account with two-factor authentication needs an app password, created in Stalwart's own settings.
Everything else — TLS, running immutably, several Stalwart servers, settings the installation decides, every environment variable — is in Installing and Configuring.
Development
npm install
npm run dev:mock # built-in mock Stalwart ([email protected] / demo)
npm test
Architecture, the mock's switches and how versions are numbered are in CONTRIBUTING.md.
Contributing
CONTRIBUTING.md · CODE_OF_CONDUCT.md · SECURITY.md — please report vulnerabilities privately.
License
Copyright (C) 2026 Coffey Labs — AGPL-3.0-or-later. See LICENSE.
If you run a modified ihasmail, set SOURCE_URL to your own repository: the
sign-in page and Settings › About both show it. See
Rebranding.






