Linus Rath a8cccf1ad1 fix: keep occurrence alert edits on 1.0 and count the organizer
Fixes from a second review of the Stalwart 1.0 calendar work.

- Changing the alerts of one occurrence of a series that uses the
  calendar's default alerts said "Event updated" and kept the default
  on 1.0: while a series uses them, 1.0 shows the defaults in place of
  an occurrence's own alerts and refuses `useDefaultAlerts` on a single
  occurrence. The series now stops using the defaults first, keeping
  the alerts it shows under ids of their own, and then the occurrence's
  alerts go out. 0.16.23 showed the edit already and still does.
- The participant limit counts the organizer entry a save adds (live on
  1.0: 19 attendees and the organizer are accepted, 20 are refused), so
  the editor warned one attendee late. It warns at the limit now, and
  the warning and the refusal say the organizer counts, with plural
  forms in every locale.
- Adding or answering an invitation from the mail view, and applying a
  proposal, said "could not complete" when the server refused the
  event: the import swallowed its SetError. The banner now asks the
  import to reject with the refusal and names the participant limit
  like the calendar does.
- A range load that finished after a later one could put back its own
  events, range or failure. Only the latest load writes the store, and
  a load for an account the user left is dropped.
- A search filter with an OR, a NOT or a condition of several keys next
  to its date bounds goes out as it is instead of being expanded, which
  1.0 refuses.
- A time zone setting typed in another letter case ("europe/berlin")
  is used as Intl spells it. 1.0 refused it as a query argument, and
  0.16 and 1.0 both dropped it from new events, which were stored
  floating.
- A failed save no longer shows the store's English toast next to the
  translated message.
- Tests for a limited read that asks later chunks of a request again
  after a refused chunk or a full page.
2026-09-25 21:21:28 +02:00
2026-09-23 21:18:21 +02:00
2026-09-23 21:18:21 +02:00
2026-09-23 21:18:21 +02:00
2026-09-23 21:18:21 +02:00

Bulwark: webmail for Stalwart Mail Server. Mail, calendar, contacts and files in one browser client.

latest release  docker: ghcr.io/bulwarkmail/webmail  license: AGPL v3  Discord members online

Website · Documentation · Live demo · Releases · Discord

Bulwark Webmail is a self-hosted webmail client for Stalwart Mail Server. It talks to Stalwart over JMAP and puts mail, calendar, contacts and files behind one login, with one set of settings and one admin dashboard.

Bulwark inbox on a laptop, with the same message open on a phone

Contents

Screenshots

Calendar week view with events from several calendars Contact details with recent mail and upcoming events
Calendar week view  ·  Contact details with recent mail and upcoming events

Rich-text composer next to the message list The inbox split diagonally between the light and dark theme
Composer with identities and formatting  ·  Light and dark themes

Features

  • Mail: threading, unified inbox, cross-account views, full-text search, Sieve filters, S/MIME, templates, scheduled send
  • Calendar: month, week, day and agenda views, recurring events, iMIP invitations, CalDAV subscriptions
  • Contacts: several address books, groups, vCard import and export
  • Files: Stalwart's JMAP file storage, with previews, sharing and folder upload

All four share single sign-on and 2FA, multiple accounts, 27 languages, PWA install and web push, themes, plugins and keyboard shortcuts. The full list is on the All features page.

There are two editions. The full edition runs as a Node.js server and adds the admin dashboard, OAuth, plugins and settings sync. Bulwark Lite is the same client as static files, served by any web host or by Stalwart itself.

Quick start

docker run -d -p 3000:3000 ghcr.io/bulwarkmail/webmail:latest

Then open http://localhost:3000. A setup wizard asks for your Stalwart server and an admin password. The installation guide has the details, and Stalwart setup covers the mail server side.

Other ways to install

Method Guide
Docker Compose Compose
Behind a reverse proxy or on a sub-path Reverse proxy
From source, without Docker Manual install
Lite on any static host Static hosting
Lite as a container Container image
Lite served by Stalwart Install on Stalwart

Updating explains how to move to a new version.

Configuration

Most installs are set up in the wizard on first launch and changed later in the admin dashboard. You can also use environment variables, which fit read-only or immutable deployments better. When both set the same key, the value saved in the admin config wins, so an environment variable only fills in what the admin config leaves unset.

JMAP_SERVER_URL=https://mail.example.com
APP_NAME=My Webmail
Topic Guide
Overview, config files and precedence Configuration
Every variable Environment reference
OAuth2 / OIDC and single sign-on Authentication, Embedded SSO
Several JMAP servers, custom endpoints Multi-server deployments, Custom endpoints
Branding, logos, per-domain branding Customization
Anonymous telemetry (off by default) Anonymous usage stats

Documentation

All documentation is at bulwarkmail.org/docs:

The pages are Markdown files in the website repository. Send corrections there.

Development

git clone https://github.com/bulwarkmail/webmail.git
cd webmail
npm install
cp .env.dev.example .env.local   # built-in mock JMAP server, no mail server needed
npm run dev
npm run typecheck
npm run lint
npx vitest run             # unit tests
npm run test:integration   # Stalwart in Docker + Playwright

The contributing guide covers tests, translations, code style and pull requests. Architecture explains how the code is organized.

The stack: Next.js 16 and React 19, TypeScript, Tailwind CSS v4, Zustand, Tiptap, next-intl, Tabler Icons, and our own JMAP client (RFC 8620). Tests run on Vitest and Playwright.

Community and support

License

GNU AGPL v3. This repository preserves the original MIT attribution for the fork lineage in NOTICE.

Acknowledgments

Thanks to root-fr/jmap-webmail and @ma2t for the groundwork this project builds upon.

S
Description
Self-hosted JMAP webmail for Stalwart Mail Server. Mail, calendar, contacts, and files in one client.
Readme Multiple Licenses
80 MiB
Languages
TypeScript 98.3%
JavaScript 0.9%
CSS 0.4%
Shell 0.3%