Request offline_access so the IdP issues a refresh token, and add an
OAUTH_SCOPES override for providers that reject or extend the default
list. Closes#104
The button in Settings > Identities opened the identity manager, which
says nothing about sub-addressing. The info row keeps the explanation;
acting on +tag mail (auto-filing into folders) is planned as part of
the filter rule builder. Refs #76
Keycloak rejects an end-session request that carries
post_logout_redirect_uri without id_token_hint or client_id. Store the
id_token from the token exchange in an httpOnly cookie, pass it as
id_token_hint together with client_id on logout, and clear it with the
refresh token.
Fixes#102
Locks in the single-link behaviour Firefox depends on: badge by
mutating the existing icon link, restore the original href on zero
count and on unmount.
Favicon badge: mutate the existing icon link href so Firefox picks up
the badge; strokeRect fix for the Safari <=15 fallback. Resolved the
zero-unread repaint in favour of the href-restore approach.
Security: upgrade Next.js 16.2.4 -> 16.2.6 to patch CVE-2026-44578
(GHSA-c4j6-fc7j-m34r, CVSS 8.6, unauthenticated WebSocket-upgrade
SSRF on the built-in Node server) and eleven other May 2026
advisories bundled in the same release. next-intl patched for
GHSA-4c35-wcg5-mm9h prototype pollution in the experimental
precompile path. React/react-dom rolled forward to 19.2.6.
Fixes:
- bulk delete now honours the "delete to trash" setting instead of
always hard-deleting
- favicon repaints the base icon on zero unread so the badge clears
- Delete app/favicon.ico so Next.js renders a single <link rel="icon">
for icon.svg. With two icon links in the DOM, browsers disagreed on
which to use: Chrome and Firefox on Linux both picked the *first* one,
making the dynamically-appended badge link invisible.
- Mutate href on the existing <link> instead of injecting a second one.
Firefox only updates the tab icon when the href of the element it
already tracks changes — adding new <link> nodes dynamically is ignored.
- Simplify image loading: replace fetch → blob → FileReader → Image
chain with new Image() + crossOrigin="anonymous".
- Fix badge border in Safari 15 fallback: use strokeRect instead of
stroke() after fillRect (fillRect does not add to the canvas path).
- Attachments from providers that stamp a Content-ID on every part
(e.g. Gmail) now show in the attachment panel; previously they were
silently filtered out as "inline" even when the HTML body never
cited their cid. The viewer now parses the body for actual cid:
references and treats only those attachments as inline (#58).
- Email-to-self no longer gets discarded as a duplicate by the
sender's own MTA. The send flow keeps the outgoing message in
Drafts during submission and uses EmailSubmission.onSuccessUpdate\
Email to move it to Sent only after SMTP has accepted it, so the
inbound delivery for self-send doesn't match a pre-existing
Message-ID in the account (#60).
Thanks @melges-morgen and @tamisoft for the reports.
Community PRs and targeted feature work. Highlights:
Features
- Archive now operates on the whole conversation, matching Gmail (#49)
- Russian and Ukrainian locales, full translation sets (#59 @VsevolodSauta)
- Custom favicon with unread badge painted over the base mail icon;
also fixes stale sidebar counters on JMAP push (#63 @jabiinfante)
- Optional domain-favicon avatars with a privacy-preserving proxy and
a freemail denylist so the same provider logo isn't shown for every
sender on a shared host (#22)
Fixes
- Print (Ctrl+P, button, menu) produces a clean single-column page for
plain text and HTML emails alike, with actions/reply panels hidden,
dark-mode overridden, and wide newsletters shrunk to fit A4
- Contacts now load past 500 entries by batching ContactCard/get to
the server's maxObjectsInGet (#45 @capitanroy, #46)
- Sieve filter destinations use the full Parent/Child folder path so
Stalwart can resolve them (#62 @travier)
- OIDC over plain HTTP shows a clear HTTPS-required banner instead of
throwing crypto.subtle is undefined (#23 @jothoma1)
- Missing contacts delete-confirm translation keys added to every
locale (only Dutch had them before)
- Favicon badge hook stopped tearing out Next.js's managed icon link,
fixing a parentNode-is-null crash on route changes
- Contact empty-state action buttons fit their container (#56)
- Print layout excludes sidebar/list (#55 @prastowoagungwidodo)
Docs
- README example for OAUTH_ONLY=true to disable Basic Auth (#61
@travier)
Infrastructure
- Container images also published under jmap-webmail:1 for major-tag
pinning (#57 @joelpurra, closes#54)
Defense-in-depth. All current callers pass hardcoded tailwind class
strings, so this is not exploitable today, but a future caller that
forwarded a user-controlled value would get HTML injection through the
class attribute. Run the value through escapeHtml() and add a test
covering the attribute-escape case.
The plain-text email renderer escaped <, >, and & before building anchor
tags for linkified URLs, but did not escape " or '. A crafted URL
containing a quote broke out of the href attribute and could inject
event handlers into the rendered HTML. Affects both the single-email
viewer and the threaded conversation view.
Fix by extracting a shared plainTextToSafeHtml helper that escapes all
five HTML-significant characters in the correct order before
linkification. Both views route through it. Regression tests parse the
output and assert no event handler lands on the anchor element.
Reported privately by Linus Rath. Thank you for the responsible
disclosure.
Also bumps dependencies flagged by npm audit:
- Next.js 16.1.5 -> 16.2.4 (DoS in Server Components)
- next-intl 4.5.8 -> 4.9.1 (open redirect)
- DOMPurify 3.3.1 -> 3.4.0 (FORBID_TAGS bypass)
- picomatch, vite, brace-expansion resolve transitively
Also carries the Apache JAMES compose fix from the 1.4.0 cycle (explicit
text/plain type on textBody per RFC 8621 section 4.1.4) and the missing
email_viewer.send translation.
Release 1.4.1.
* feat: open event modal on month day cell click
* feat: suggest first available hour when creating from month view
* chore: document month view slot suggestion helpers
* fix(calendar): use double-click to create event in month view
* fix(calendar): use 9am fallback for non-today month slots
Bottom nav now renders on tablet/landscape viewports (768-1023px) across
Mail, Calendar, and Contacts. Added z-index for proper layering and
removed redundant active tab indicator bar.
* fix: more margin on the avatar to align with subject
* fix: fixed multi day events multiple items gap spacing
* fix: align sticky week headers with calendar grid
* fix: account for sticky header in week view initial scroll
New features:
- Sandboxed iframe rendering for rich HTML emails (CSS isolation)
- Mobile bottom action bar (Reply, Archive, Delete, More)
- Long-press context menu with haptic feedback on touch devices
- Tag counts sidebar section with batch JMAP queries
- Empty folder for Junk/Trash with batch delete progress
- Extra-compact density option (28px desktop, 44px touch)
- SPF/DKIM/DMARC security tooltips with plain-language explanations
- Resizable sidebars with drag, touch, and keyboard support
- Expandable sender info panel in email viewer
- API retry with exponential backoff for transient JMAP failures
- OAuth-only mode (OAUTH_ONLY env var)
Improvements:
- CSS-first responsive layout (no blink on orientation change)
- Touch-friendly context menu submenus (tap-to-expand)
- Click-to-toggle more-actions dropdown (was hover-only)
- Wide HTML emails horizontally scrollable in iframe
- All 8 locales updated with new translation keys
- Keep show/hide details button in place when expanded (#18)
- Use i18n translations for details toggle text
- Split instrumentation for Edge Runtime compatibility
- Patch minimatch ReDoS (CVE-2026-27903)