Comparison
ihasmail and Bulwark Webmail
We get asked this often enough that a straight answer is more useful than a diplomatic one. Both are self-hosted JMAP webmail clients for Stalwart. Both are AGPL. Both do mail, calendar, contacts and files. They are built on opposite instincts about how much a webmail should keep, and neither instinct is wrong — they suit different people. Here is what actually differs, so you can decide which one that is.
We are not neutral about our own product and it would be silly to pretend otherwise. What we can do is state their side from their own documentation rather than from our impression of it, mark the places where they have something we do not, and not read silence as absence. Where their docs do not cover something, this page says so instead of guessing.
Checked 2 September 2026 against their README at the commit dated 1 September 2026. Both projects move quickly; if something here has gone stale, tell us and we will fix it.
The one difference the rest follows from
Everything below is downstream of a single decision: how much the webmail keeps of its own.
ihasmail keeps nothing
There is no database, no config directory and no admin UI. Configuration is
environment variables; your settings live in a settings.json
inside your own JMAP Files store on Stalwart, so they follow the account
rather than the install. With IMMUTABLE=1 the container runs
read-only with no volume at all.
What that buys. Nothing to back up, migrate or restore, and an instance that can be deleted and recreated from the image and a handful of variables.
What it costs. Sessions live in memory, so every deploy signs everyone out. There is no admin dashboard, and a configuration change means restarting the container. Nothing can be customised per domain at runtime, because there is no runtime state to hold the customisation.
Bulwark keeps an admin layer
A setup wizard on first launch writes to an admin config directory, and an admin dashboard edits it afterwards. That directory is what makes the rest of their feature set possible: a plugin store, uploadable themes, per-domain branding, multiple JMAP servers picked by domain, and admin-enforced presets.
What that buys. An operator can change things without a redeploy, and an installation can be shaped for its users rather than for its image.
What it costs. The directory is durable state: it has to be
preserved across upgrades and backed up with everything else, and two installs
of one image are not the same thing until it is. Their docs note that
environment variables also work and suit read-only infrastructure, with a
variable overriding the admin-managed value and
ADMIN_CONFIG_READONLY locking the directory after setup — so the
cost is avoidable, at the price of not using the wizard the product is built
around.
Put plainly: ihasmail has no admin dashboard and is not getting one, because Stalwart already has one. Stalwart's web admin is where accounts, domains, queues, TLS, Sieve at the server level and the rest are managed, and rebuilding a second one in the webmail would be duplicating a thing that already exists and works.
There is a security argument for the split as well as a tidiness one. Administration and reading your mail are different jobs for different people, and keeping them on separate surfaces means the administrative one can be locked down on its own terms — reachable only from inside the network, or on a different host, or behind separate credentials — without any of that touching the client every user signs into daily. A dashboard reached from the same origin as the mailbox is a larger surface to defend, and defending it well is work we would rather not have to be good at.
That is a trade rather than a free win, and the cost is real: anything ihasmail itself does needs an environment variable and a restart, and an operator who wanted one place to change everything has two. If you want a container you can delete and recreate with nothing to restore, that is the thing we optimised for and the reason the rest of this page reads the way it does.
Side by side
| ihasmail | Bulwark Webmail | |
|---|---|---|
| Protocol | JMAP only. No IMAP, POP3 or SMTP fallback | JMAP, plus CalDAV subscriptions in the calendar |
| Stack | Vite, React 19, TypeScript. The client is a plain static bundle that will sit on any static host or CDN; only the thin Node/Hono proxy behind it needs a runtime, and it holds no state | Next.js 16 App Router, React 19, TypeScript, Tailwind v4, Tiptap editor |
| Persistence | None. No database, no config directory; IMMUTABLE=1 runs read-only with no volume |
Admin config directory written by the setup wizard; optional encrypted settings data directory; can be locked read-only after setup |
| Configuration | Environment variables only, plus an optional read-only settings policy file. Restart to change | Setup wizard and admin dashboard, or environment variables, which override admin-managed values |
| Apps | Mail, calendar, contacts, files, Sieve filters | Mail, calendar, contacts, files, Sieve filters |
| Three-pane, conversation view, virtualised list, Gmail-style shortcuts and search operators, scheduled send, undo send, multiple floating composers, templates, labels as IMAP keywords, read receipts, multiple identities | Threading, unified inbox, cross-account view, full-text search, templates, S/MIME, a comparable shortcut set | |
| S/MIME | No. On the backlog, not built | Yes, in mail |
| Calendar | Month, week, day, agenda; recurrence-rule builder; drag to reschedule; free/busy lookup; iMIP invitations; colour categories synced as JSCalendar; message to event; iCAL import and export; read-only calendar subscriptions by URL; birthdays derived from contacts | Month, week, day, agenda; recurring events; drag to reschedule; iMIP invitations; CalDAV subscriptions |
| Multiple servers | One Stalwart at a time. Other people's calendars, address books and files appear through JMAP sharing, with per-collection accept and withdraw | Several JMAP servers, picked by domain, with unified and cross-account views |
| Multi-tenancy | Whatever Stalwart does. Multi-tenancy is a Stalwart enterprise feature and ihasmail does nothing that gets in its way — one instance serves a multi-tenant server as it comes | Also a Stalwart concern, and separately their own multi-server support covers one client per server |
| Sign-in | Stalwart credentials; signs in with a TOTP code where the account has two-factor on, though enrolling is not offered in the client yet; app passwords per device; sessions server-side with the upstream credentials sealed | OAuth2 and OIDC with auto-discovery, an OAuth-only mode and automatic SSO, or basic auth; session credentials encrypted in an httpOnly cookie |
| Extensibility | None. Single-purpose client, no plugin API | Plugin system with bundled and marketplace plugins, a development directory, and uploadable theme packages |
| Theming | Built-in palettes with light and dark modes and a separate accent, chosen per reader; no uploadable themes | Uploadable theme packages, and themes distributed through the marketplace |
| Branding | APP_NAME at runtime with no rebuild; logo, icons and favicons are static files a deploy can swap; accent colours are in the bundle and need a rebuild. One brand per instance, not per domain. The AGPL source-offer obligation is documented |
Per-domain overrides, custom logos, favicons and colours, login page customisation, build-time locale and base path |
| Languages | English plus nine, all machine-translated and marked beta; about 620 CLDR locales for dates and numbers | 27 |
| Telemetry | None, and nothing to opt into | Anonymous, opt-in, off by default, documented as carrying no personal data |
| Licence | AGPL-3.0-or-later | AGPL v3, forked from an earlier MIT-licensed project whose attribution is preserved in their NOTICE |
| Stalwart version | 0.16 or newer; 0.15 support frozen on a tag, with a migration tool | Not stated in the material reviewed |
What "no plugins" actually means here
The row above says ihasmail has no plugin system, which is true and reads worse than it is. There is no way to add a capability that is not in the build — but a good deal of what an extensible client gets extended with is already here as a switch. Bulwark publishes its plugins in a separate repository, which makes the two approaches unusually easy to line up. Their catalogue, and what stands in its place here:
| Their plugin | Here | |
|---|---|---|
| external-mail-warning | Built in, reader setting | Banner on mail from outside the domains you list |
| external-link-warning | Built in, reader setting | Interrupts links to domains you have not trusted |
| reply-all-guardrail | Built in, reader setting | Asks again past a recipient count you pick |
| send-later | Built in | Scheduled send, where Stalwart has futureRelease |
| spam-score | Built in | Reads the score the server already put in the headers |
| calendar-agenda | Built in | One of the four calendar views |
| auto-tag | Sieve rules | Rule builder or raw script, run server-side rather than in the client |
| gravatar, libravatar | Different by choice | Avatars come from the contact's own photo, or generated initials. No third-party lookup, which would tell someone else who you correspond with |
| outlook-style-headers | Not offered | One header layout, not a choice |
| impersonation-notice | Partly | The outside-sender banner covers the common case; there is no display-name lookalike check |
| smime | Not built | On the backlog |
| jitsi-meet | Not built | Virtual locations on an event are shown and linked, but nothing is integrated |
| nextcloud-attachments | Not built | Attachments go through JMAP Files on your own server |
| translate | Not built | Would mean sending message text to a third party |
| quick-notes | Not built | — |
| email-stats | Not built | — |
Six of their nineteen are things ihasmail does without being asked to, two are scaffolding for plugin authors rather than features, and six are genuinely absent here — S/MIME being the one people ask for. Two we have deliberately declined: avatar lookups and translation both work by sending something about your mail to somebody else's server, which is a fair trade for many people and not one we make on their behalf.
And the rest of the switches
Sixty-seven settings in all. A sample of what else is a toggle here, and who turns it on.
| Built in | Switched by | |
|---|---|---|
| Outside-recipient confirm | the reader | Asks before a reply leaves the organisation |
| Attachment reminder | the reader | Catches "see attached" with nothing attached |
| Remote-image proxy | operator and reader | IMAGE_PROXY for the instance, then a per-sender trust list |
| Read receipts | the reader | Request them, and choose what to do when one is asked of you |
| Undo send | the reader | A window you set in seconds, or off |
| Templates | the reader | Reusable bodies with placeholders |
| Labels | the reader | IMAP keywords with colours, so they follow you to other clients |
| Calendar subscriptions | the reader | Read-only calendars by URL |
| Birthday calendar | the reader | Derived from contacts, stored nowhere |
| Palettes and accent | the reader | Light and dark modes, chosen separately from the palette |
| Swipe actions | the reader | Left and right, on touch |
| Sort presets | the reader | Multi-level, and scoped per folder if you want |
| App passwords | the reader | Per device, revocable |
| Defaults and locks | the operator | Seed any of the above for new accounts, lock them, or turn one on once for people already here |
The trade is the honest one, and it runs both ways. Everything here arrived because somebody asked and it was built, which is slower than installing a plugin and means a capability nobody has asked for is simply absent. Their model adds things without a release; ours means there is nothing to install, sandbox, keep up to date or trust. If what you want is on these lists, it is a switch. If it is not, it is an issue and a wait — or the other client.
Which one to pick
Genuinely a question about your deployment rather than about the software.
Bulwark probably fits better if
- you want an admin dashboard and a setup wizard rather than environment variables
- you run more than one JMAP server, or want unified views across accounts
- you need S/MIME today
- you want different branding per domain from one instance, or plugins and themes
- SSO through OAuth or OIDC is a requirement
- you need a language we have not translated
ihasmail probably fits better if
- you want a container with nothing to back up, migrate or restore
- a read-only filesystem with no volume is a requirement rather than a preference
- one Stalwart is all you point at — including a multi-tenant one, which ihasmail serves as it finds it
- you would rather configure by environment variable and redeploy than click a dashboard
- you want the client to be the only moving part
There is no third option being sold here. Bulwark is a good client built by people who chose differently, and on the questions that matter most to a lot of operators — SSO, plugins, several servers, S/MIME — they are ahead of us and we are not planning to catch up on all of it. If those are your questions, use theirs. If "what does this container keep?" is your question, that is the one we set out to answer.
Something wrong or out of date on this page? Open an issue — including if you work on Bulwark and we have misrepresented you.