Commit Graph
39 Commits
Author SHA1 Message Date
Linus Rath 16e88e8a1b fix: end every push with a notification so Safari keeps the subscription #1322 2026-10-24 17:58:21 +02:00
Linus Rath a037f9a6e9 fix: do not offer push onboarding while the resync is restoring the subscription #1321 2026-10-22 23:15:32 +02:00
Linus Rath 6b0c345cf7 fix: keep push notifications silent when the notification sound is off #1289 2026-10-19 18:40:06 +02:00
Linus Rath 41a52ec53b docs: refresh the readme images and the web app manifest screenshots from the new demo 2026-10-18 20:38:44 +02:00
Linus Rath 4c0017d0c1 feat: rework the demo around one persona with two accounts and a shared mailbox
The demo user becomes Nora Lindqvist, engineering lead at Meridian Labs,
in the week of a product launch. The fixtures tell one story across mail,
contacts, calendar, tasks and files, and exercise the features the
screenshots and the public demo should show:

- a second, mail-only login (her personal domain) and the shared Support
  mailbox delegated to the work account, so the account switcher, the
  shared section and the merged inbox have real content
- raw headers the way Stalwart writes them: the sender check fails on
  the phishing mail, newsletters carry a one-click unsubscribe, one mail
  asks for a read receipt, and spam scores show in the details
- an iMIP invitation with a served .ics, an event waiting for the answer
  on the calendar, and RSVP patches applied in the demo client
- @mentions as mailto links in a received mail, a verification code
  twelve minutes old, nested folders, named tags on the mail, contact
  groups, a scheduled message and tasks switched on
- every attachment and file backed by real bytes under public/demo,
  generated by `scripts/demo-assets/generate.mjs`; contact photos are
  bundled portraits instead of requests to randomuser.me
- folder counts computed from the mail instead of hand-kept numbers

Demo login seeds the tags, templates and merged-inbox settings once per
device and switches the cross-account gate on for the session; "Reset"
restores them. `bulwark-demo-simulate=off` in localStorage stops the
simulated incoming mail for screenshot runs.
2026-10-18 19:48:11 +02:00
Linus Rath 868805ec9a fix: keep ringing for a second mail in the same account #1141
The quiet window ignored which account rang, so a second, different
message in the same account within 30 seconds arrived without sound, and
every single-login user lost the alert too. The window now records the
account of the last audible alert and silences only other accounts,
which is the burst across logins the change is meant for.
2026-10-01 11:02:39 +02:00
lucamzanon cd39805566 feat(push): ring once for a burst of mail across accounts
Each account has its own notification, so one message reaching several
of the user's accounts rang once per account. Only the first alert in a
30 s window makes a sound now; the others still appear or update,
silently. The window runs from the last audible alert, so a steady
trickle still rings every so often.
2026-10-01 04:40:08 +02:00
Linus Rath 4858eb0915 fix: open a push notification's message in the account it came from
Clicking a new-mail notification opened `/mail/message/<id>` in
whichever account was active. With several accounts signed in, that
looked the id up in the wrong account: nothing opened, or a different
message did and was marked read.

The preview API now returns the cookie slot of the login that owns the
notified account, the service worker adds it to the permalink (or links
that account's Inbox for a group notification), and the app switches to
the login on that slot before opening the message.
2026-09-26 16:12:20 +02:00
Linus Rath f086d21d84 docs: use framed standard-theme screenshots in the readme 2026-09-22 23:04:27 +02:00
Linus Rath 9e2c1dac85 chore: remove unused e2e smoke tests and leftover assets 2026-09-21 23:02:40 +02:00
Linus Rath bf33165ffb Merge pull request #914 from bitfactory-dk/fix/notification-click-focus-before-navigate
fix(sw): focus the client before navigating on notification click
2026-09-07 17:55:44 +02:00
Michael Richter 9b23b99cc1 fix: smaller margin for PWA icons #883 2026-08-28 15:31:42 +02:00
Linus Rath 63fa2d2d93 fix: stop notifying for spam by using the JMAP emailPush delivery filter 2026-08-26 21:45:12 +02:00
bitfactory 79e8bbf983 fix(sw): focus the client before navigating on notification click
Clicking a push notification on Android closed the notification and did
nothing: the app never came to the front.

handleNotificationClick navigates an existing client and then focuses it:

    if ("navigate" in client && targetUrl) {
      await client.navigate(targetUrl);
    }
    return client.focus();

A notification click grants the service worker a transient user
activation, and both focus() and openWindow() refuse to run without one.
navigate() spends that activation, and it also replaces the client's
document, which invalidates the WindowClient handle the next line uses.
So navigating first breaks the click two ways over.

Instrumented on a device, against a backgrounded installed PWA:

  client 1: navigate ok -> focus() threw NotFoundError      (stale handle)
  client 2: navigate ok -> focus() threw InvalidAccessError (activation spent)
  openWindow()          -> threw InvalidAccessError         (same)

Every rejection was swallowed by the surrounding catch, so the toast
closed and nothing opened, with nothing in any log to say why.

Focusing first uses the activation while it is still live. navigate()
needs none of its own once the client is focused, and it is wrapped so a
failed navigation still leaves the app raised rather than falling through
to opening a second window.

Running in production since 2026-08-24.
2026-08-26 01:40:18 +02:00
Shuki Vaknin d29ab9b552 feat(push): group new-mail notifications per account instead of one per message
Each email push showed a notification with a unique tag
("bulwark-mail:<id>"), and Android renders one notification per unique
tag — so a burst of mail stacked one toast per message (50 arrivals =
50 toasts).

Use a shared per-account tag ("bulwark-mail:<accountId>") so each push
replaces the account's single notification. The newest message stays the
headline and a Gmail-style "+N more messages" line, counted from the
account's unread total, carries the rest. A single unread still deep-links
to that message on click; a group opens the inbox.
2026-08-21 18:48:04 +03:00
Linus Rath e2da05c130 feat: deep links for mail, calendar, contacts, files, settings and improve screen reader support
#733 #722 #721  #720  #719
2026-08-06 16:47:20 +02:00
Steven RYDELLandCursor b1b09d54c8 feat(pwa): add Apple Touch icons for iOS home screen
- Add apple-touch-icon.png (180x180) - default iOS icon
- Add apple-touch-icon-120x120.png - iPhone retina
- Add apple-touch-icon-152x152.png - iPad retina
- Add apple-touch-icon-167x167.png - iPad Pro
- Add apple-touch-icon-180x180.png - iPhone Plus/Pro

iOS automatically detects these icons when users add the PWA to their home screen.
No code changes required - icons are discovered by convention.

Fixes: PWA icon not appearing on iOS home screen
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-05 19:51:06 +02:00
dealerweb 4d6b4b5b8e Fix: brand push notifications with the configured PWA icon
The service worker hard-coded the notification icon and badge to the bundled /icon-192x192.png, so push notifications always showed the default Bulwark logo even when an admin had configured a custom PWA/favicon icon (which the manifest already honors via /api/pwa-icon).

Point both notifications at /api/pwa-icon/192, and make that endpoint fall back to the bundled default icon instead of returning 404 when no custom icon is set - so it always returns an app icon and the service worker (which can't run the custom-vs-default check itself) has a single stable URL.
2026-07-04 14:56:19 +02:00
Linus Rath bb7e1c4538 fix: per-account push subscriptions so multi-account notifications work #298 2026-05-16 22:50:01 +02:00
Lucas Gaitzsch 3f444a8912 Feature/protocol handlers
* Added account selection for protocol links when multiple connected accounts are available, including mailto: links
* Added support for handling mailto: links in an already-open PWA/session instead of always opening a new tab
* Added webcal: protocol handling for calendar links
* Added account selection for webcal: links when multiple calendar-capable accounts are connected
* Added an import-or-subscribe choice for detected webcal calendars
* Added protocol handler settings for registering mail and calendar handlers and choosing the open mode
* Added service worker/session coordination for passing protocol requests between browser/PWA contexts
* Added tests and translations for the new protocol handler flows
2026-05-12 20:49:05 +02:00
Linus Rath f970fd1822 feat: add plugin hooks for compose, attachments, search, lifecycle, and routing 2026-05-02 21:27:56 +02:00
Linus Rath 841513e510 feat: support subpath deployment with NEXT_PUBLIC_BASE_PATH environment variable 2026-05-01 14:57:49 +02:00
Linus Rath 31d17098d6 feat: open mail from push notification clicks 2026-05-01 02:13:25 +02:00
Linus Rath 3f97e6ed8d fix: scope email notifications to genuine inbox deliveries 2026-05-01 02:08:13 +02:00
Linus Rath 2dea33e698 feat: improve new email push notification logic for inbox 2026-05-01 01:57:57 +02:00
Linus Rath f3d9115ecd feat: web push notifications for PWA #233 2026-05-01 00:26:48 +02:00
nesgarbo 028e78a0c9 fix: serve PWA manifest dynamically to respect runtime APP_NAME env var
Delete static public/manifest.json (hardcoded "Bulwark Webmail") and mark
app/manifest.ts as force-dynamic so Next.js evaluates APP_NAME at request
time instead of build time, fixing the native browser install prompt.

Closes #207
2026-04-18 13:20:14 +02:00
Linus Rath 440a4e919a Revert "perf: make root HTML cacheable by dropping per-request CSP nonce"
This reverts commit 522bf6a019.
2026-04-18 13:10:42 +02:00
Linus Rath 522bf6a019 perf: make root HTML cacheable by dropping per-request CSP nonce 2026-04-18 13:01:12 +02:00
Linus Rath 88d87be685 fix: correct PWA icons with proper sizing, transparency, and dark/light mode support 2026-04-10 19:26:12 +02:00
Linus Rath 790d7084af fix: restore service worker and add manifest icons 2026-04-09 22:19:56 +02:00
Linus Rath 0d4b588fd0 feat: add Latvian (lv) locale support 2026-04-08 22:42:56 +02:00
Linus Rath 6a725dde58 feat: add Latvian (lv) locale support 2026-04-08 22:42:15 +02:00
Linus Rath 5aad97d64e feat: add PWA support with service worker and install prompt 2026-04-03 04:39:19 +02:00
Linus Rath 8eff9fdfab feat: add notification settings with sound picker and preview 2026-03-22 01:55:21 +01:00
Linus Rath 2fe1b01d4d feat: add configurable logo to login page with light/dark mode support
- Display Bulwark logo on the login page, with theme-aware switching
  between light and dark variants based on the resolved theme
- Add LOGIN_LOGO_LIGHT_URL and LOGIN_LOGO_DARK_URL env variables to
  allow custom logo overrides (defaults to bundled Bulwark branding)
- Expose logo config through /api/config endpoint and useConfig hook
- Add logo URL prompts to the setup.sh installer branding step
- Rename branding assets to use underscores instead of spaces
2026-03-13 19:45:09 +01:00
Linus Rath 9438cf75ab Update logos to use lettering variants with light/dark mode support 2026-03-13 14:30:39 +01:00
Linus Rath 091c10d828 Add branding assets, update logos in README/CONTRIBUTING/ROADMAP, replace favicon with SVG icon 2026-03-13 14:27:35 +01:00
Matthieu MALVACHE cf21a84263 Initial release: JMAP Webmail Client
A modern, privacy-focused webmail client built with Next.js and the JMAP protocol.
Designed for Stalwart Mail Server.

Features:
- Full email operations (compose, reply, forward, threading)
- Real-time push notifications
- Dark/light theme support
- Mobile responsive design
- Keyboard shortcuts
- Drag-and-drop organization
- i18n (English/French)
- Security-first (external content blocked, HTML sanitization)
2025-12-10 17:54:22 +01:00