Say what "even when ihasmail is closed" actually means

Web Push works, confirmed end to end against the live 0.16.19: with
Chrome open and every ihasmail tab closed, a notification arrives
immediately and names the sender and subject.

But "closed" means ihasmail, not the browser, and the switch did not say
so. Web Push is delivered over a connection the browser holds, so
something of it has to be running.

Observed on 2026-08-26, with Chrome fully quit and "Continue running
background apps" off: nothing arrived until Chrome was started again, at
which point the queued notification was delivered. Turning that setting
on keeps a process alive and restores immediate delivery.

Worth knowing that the queue is not indefinite -- a Web Push message
carries a TTL, and one that expires before the browser comes back is
dropped rather than delivered late. Being an installed PWA does not
change any of this on a desktop; it changes the window, not who holds
the connection. On Android it would, since the push service can wake the
browser from cold.

None of this is ihasmail's to fix. It is what Web Push is, and the only
thing worth doing about it is not implying otherwise -- which the
notification switch was quietly doing.
This commit is contained in:
2026-08-26 14:13:19 -07:00
parent 99e98f82f3
commit 7726665a48
2 changed files with 3 additions and 3 deletions
+1 -1
View File
@@ -76,7 +76,7 @@ seconds of downtime with nothing lost.
- Search with Gmail operators (`from:`, `to:`, `subject:`, `has:attachment`, `is:unread`, `is:starred`, `in:`, `label:`, `before:`, `after:`, `larger:`, `smaller:` …) plus an advanced-search panel - Search with Gmail operators (`from:`, `to:`, `subject:`, `has:attachment`, `is:unread`, `is:starred`, `in:`, `label:`, `before:`, `after:`, `larger:`, `smaller:` …) plus an advanced-search panel
- Composer: multiple floating/minimised/maximised composers, rich-text editor (formatting, lists, links, colours, images pasted/dropped inline, emoji), plain-text mode, recipient chips with autocomplete from **contacts, the directory (GAL) and recent recipients**, multiple identities with HTML signatures, Cc/Bcc, priority, read-receipt request, templates/canned responses, attachment upload with progress, drag & drop, attachment reminder, **undo send**, **scheduled send** (quick picks or an exact date and time; the message waits in the server's queue, so it goes out whether or not ihasmail is open), autosaved drafts, reply/reply-all/forward with quoting and inline images preserved - Composer: multiple floating/minimised/maximised composers, rich-text editor (formatting, lists, links, colours, images pasted/dropped inline, emoji), plain-text mode, recipient chips with autocomplete from **contacts, the directory (GAL) and recent recipients**, multiple identities with HTML signatures, Cc/Bcc, priority, read-receipt request, templates/canned responses, attachment upload with progress, drag & drop, attachment reminder, **undo send**, **scheduled send** (quick picks or an exact date and time; the message waits in the server's queue, so it goes out whether or not ihasmail is open), autosaved drafts, reply/reply-all/forward with quoting and inline images preserved
- Live updates via JMAP push (EventSource proxied server-side) with polling fallback; desktop notifications, sound, title/favicon unread badge - Live updates via JMAP push (EventSource proxied server-side) with polling fallback; desktop notifications, sound, title/favicon unread badge
- **Notifications that arrive with ihasmail closed** — Web Push signed with VAPID ([RFC 9749](https://datatracker.ietf.org/doc/rfc9749/)), which Stalwart 0.16 supports and without which Chromium and Safari cannot receive push at all. Stalwart pushes straight to the browser's own push service: no relay, no extra service to run, and ihasmail's server is not in the delivery path. With [`emailpush`](https://datatracker.ietf.org/doc/draft-ietf-jmap-emailpush/) the payload carries the sender and subject, so the notification is useful without a round-trip — and the filter lives on the server, so spam never leaves it. The subscription is torn down on sign-out, because it belongs to the account rather than the session and would otherwise keep notifying a shared machine for a mailbox nobody is signed into - **Notifications that arrive with ihasmail closed** — Web Push signed with VAPID ([RFC 9749](https://datatracker.ietf.org/doc/rfc9749/)), which Stalwart 0.16 supports and without which Chromium and Safari cannot receive push at all. Stalwart pushes straight to the browser's own push service: no relay, no extra service to run, and ihasmail's server is not in the delivery path. With [`emailpush`](https://datatracker.ietf.org/doc/draft-ietf-jmap-emailpush/) the payload carries the sender and subject, so the notification is useful without a round-trip — and the filter lives on the server, so spam never leaves it. The subscription is torn down on sign-out, because it belongs to the account rather than the session and would otherwise keep notifying a shared machine for a mailbox nobody is signed into. **"Closed" means ihasmail, not the browser:** Web Push is delivered over a connection the browser holds, so something of it has to be running. Confirmed on 0.16.19 (2026-08-26): with Chrome open and every ihasmail tab closed, a notification arrives immediately, naming the sender and subject. With Chrome fully quit and *Continue running background apps* off, nothing arrives until Chrome is started again, at which point the queued notification is delivered. Turning that setting on keeps a process alive and restores immediate delivery. Note the queue is not indefinite — a Web Push message carries a TTL, and one that expires before the browser returns is dropped rather than delivered late. None of this is ihasmail's to fix; it is what Web Push is on a desktop, and an installed PWA does not change it (on Android it would, since the push service can wake the browser from cold)
- AZ folder list with Inbox pinned on top (other special folders mixed in), subfolders nested and collapsed by default with chevrons in their own gutter so every icon lines up; unread folders are bold (a parent is bold when a subfolder has unread mail); right-click a folder to mark it read *including subfolders*, create/rename/hide/share/empty, quota bar, Outlook-style module bar (Mail · Calendar · Contacts · Files) at the bottom of the pane, multi-account switching for shared accounts - AZ folder list with Inbox pinned on top (other special folders mixed in), subfolders nested and collapsed by default with chevrons in their own gutter so every icon lines up; unread folders are bold (a parent is bold when a subfolder has unread mail); right-click a folder to mark it read *including subfolders*, create/rename/hide/share/empty, quota bar, Outlook-style module bar (Mail · Calendar · Contacts · Files) at the bottom of the pane, multi-account switching for shared accounts
**Calendar** (JMAP Calendars / JSCalendar) **Calendar** (JMAP Calendars / JSCalendar)
@@ -71,8 +71,8 @@ export function NotificationsSettings() {
!canBackground !canBackground
? "Needs a browser with the Push API and a mail server that publishes a push key." ? "Needs a browser with the Push API and a mail server that publishes a push key."
: supportsEmailPush() : supportsEmailPush()
? "Your mail server delivers these directly to your browser, so they arrive with no tab open. The sender and subject travel in the notification." ? "Your mail server delivers these straight to your browser, so they arrive with no ihasmail tab open, naming the sender and subject. Your browser still has to be running — if you quit it completely, notifications wait and arrive when you open it again."
: "Your mail server can wake this browser, but will not include the sender or subject." : "Your mail server can wake this browser, but will not include the sender or subject. Your browser still has to be running."
} }
/> />
<Switch checked={s.notificationSound} onChange={(v) => update({ notificationSound: v })} label="Play a sound for new mail" /> <Switch checked={s.notificationSound} onChange={(v) => update({ notificationSound: v })} label="Play a sound for new mail" />