920 Commits
Author SHA1 Message Date
Linus Rath f6ad8a5942 feat: add per-message HTML/plain-text toggle #1022 2026-09-17 22:34:20 +02:00
Linus Rath bd825fb19f Merge pull request #1034 from shukiv/fix/viewer-image-own-max-width
fix(viewer): stop stretching images that carry their own max-width
2026-09-17 22:03:32 +02:00
Linus Rath ee4763d5c0 Merge pull request #1036 from dealerweb/fix/calendar-principal-fetch
fix(calendar): stop the account principal fetch from failing on every load
2026-09-17 22:03:26 +02:00
Linus Rath 0cc1602933 Merge pull request #1037 from dealerweb/fix/mini-calendar-jump
fix(calendar): jump to the day picked in the mini calendar
2026-09-17 22:03:21 +02:00
Linus Rath 2e88a0c830 Merge main into fix/calendar-participants
Resolves the two conflicts in components/calendar/event-modal.tsx created
by #967 (RSVP controls), both keep-both:

- #967's canRsvp memo and #986's resolveContactName hook are both kept;
  they are independent and were simply inserted at the same point.
- #967's RsvpBar component is kept, and StatusBadge takes #986's
  signature ({ status, t }) since #986 drops the isOrganizer prop and
  updates both call sites to match.
2026-09-17 21:54:08 +02:00
Linus Rath e2f50cbb88 Merge pull request #967 from wrycu/fix/ui-rsvp
fix: rsvp controls
2026-09-17 21:49:38 +02:00
Linus Rath 9bc54a4ef6 fix: keep security headers on dotted app paths and neutralise cid: blobs (GHSA-xvjh-v9c6-qcvc) 2026-09-17 21:08:37 +02:00
dealerweb 464586d0c1 fix(calendar): jump to the day picked in the mini calendar
Since the freely scrolling views (#759) the day, week and month views are
positioned by their own focus rather than by the selected date, and a grid
click deliberately only marks a day that is already on screen. The mini
calendar shared that handler, so picking a day there highlighted it but
left the view where it was. Give it its own handler that jumps to the day
(keeping the mobile month-to-day switch), the same path the prev/next/today
controls and deep links use.
2026-09-15 12:44:36 +02:00
dealerweb bc5302568d fix(calendar): wait for the JMAP client before loading the account principal
The calendar loads the principal's alias addresses so an alias-organised
event is recognised as the user's own. The fetch fired on mount, but after
a page load the JMAP client is restored asynchronously: the call failed
with "Not authenticated" in the console, and the once-only guard then
blocked the retry for the rest of the session, leaving the aliases empty.

Move the logic into useAccountPrincipalEmails, which waits for the client
and fetches once, and cover the sequence with a hook test.
2026-09-15 12:44:36 +02:00
Shuki Vaknin 68341a0b69 fix(viewer): stop stretching images that carry their own max-width
The viewer forces `img { max-width: 100% !important }` onto every image.
That !important also beats a sender's *inline* max-width, which breaks the
common newsletter idiom of sizing an image with max-width + max-height +
width:100%:

  <img width="200" height="134"
       style="display:block; max-height:134px; max-width:200px; width:100%;">

With the sender's max-width:200px overridden, width:100% grows the image to
the full pane, while the max-height:134px it left alone still clamps the
height - so the picture renders squashed flat.

Measured on a real Namecheap renewal notice (hero asset 300x200, natural
ratio 1.50) rendered with the viewer's own stylesheet: the hero laid out
540x134, an aspect ratio of 4.03 - stretched 2.7x. Identical at a 390px
pane. With this change it lays out 200x133, ratio 1.50.

Only force the cap on images that declare no width of their own, exactly as
the table rule alongside it already does for the same reason (#790). height
keeps its !important, so an image with a fixed inline height (the far more
common `style="width:600px;height:400px"`) is unaffected - verified
unchanged at 600x400.

Images with no inline max-width are still capped at 100%, still with
!important, so an email's own stylesheet cannot escape the pane - an email
carrying `img { max-width: none }` still measures 710px, not 2000px. An
image whose inline max-width exceeds the pane now overflows into the body's
existing horizontal scroll rather than being silently distorted: the same
trade-off #790 accepted for tables, and fitEmailBodyWidth() still scales it
to fit on a phone.

Applied to all three paths that build an email document: the reading pane,
the thread conversation cards, and the print view.

Claude-Session: https://claude.ai/code/session_019KwXZEwxijHRbfobfXmcK2
2026-09-14 20:49:04 +03:00
Linus Rath d6c923f20e Merge pull request #947 from shukiv/feat/list-attachment-chips
feat(list): show attachments on list rows and open them from there
2026-09-11 17:05:08 +02:00
Linus Rath 60b3d86004 Merge pull request #1005 from dealerweb/fix/hide-body-referenced-cid-parts
fix: hide body-embedded cid parts declared as octet-stream from the attachment list
2026-09-11 11:59:32 +02:00
Linus Rath 0b704f61e0 Merge pull request #1008 from Almost-Senseless-Coder/fix/list-label-accessibility
fix(a11y): Improved accessibility of the email list
2026-09-11 11:59:14 +02:00
dealerweb 1c00812ab7 fix: hide body-embedded cid parts declared as octet-stream from the attachment list
Some senders ship the images their HTML body embeds via cid: as
application/octet-stream with no Content-Disposition and no filename.
The body rendered them fine, but the "hide inline images" check only
recognised parts declared inline with an image/* type, so they also
showed up as nameless "Attachment" chips next to the real files.

Both viewers now scan the HTML they actually render for cid: references
(the same pattern the renderer rewrites to blob URLs) and hide a
referenced part when it is an image or generically typed. An explicit
attachment disposition always keeps its chip, as does a referenced part
with a real non-image type, since that chip is its only download. Plain
text rendering references nothing, so nothing is hidden there. The
shared rule lives in lib/attachment-visibility.ts so the desktop viewer,
the thread view and the decrypted-message path cannot drift apart.
2026-09-10 10:45:45 +02:00
Linus Rath fb24ef5d24 feat: sort contacts by last name #963 2026-09-09 19:47:33 +02:00
Almost-Senseless-Coder 4947c6c7a4 Improved accessibility of the email list 2026-09-09 19:37:43 +02:00
Linus Rath 565d5c1095 feat: choose exact-address or same-domain matching for reply from received address #1000 2026-09-09 19:27:08 +02:00
Linus Rath 9796b0b14d fix: index newer settings and flat calendar toggles in the settings search 2026-09-09 18:40:15 +02:00
Linus Rath ae403b06af feat: setting to turn off free scrolling in the calendar 2026-09-09 18:27:01 +02:00
Linus Rath 15a5497a12 feat: freely scrolling month, week and day views #759 2026-09-09 16:38:55 +02:00
Linus Rath 60e05c0041 feat: infinite scroll for the calendar agenda view 2026-09-09 15:19:53 +02:00
Linus Rath 4a057b2348 Merge pull request #990 from rotterp/fix/pro-compose-from-account
fix(pro): default the compose tab's From to the open mailbox
2026-09-07 22:39:04 +02:00
Linus Rath 26358c7a63 Merge pull request #991 from rotterp/fix/shared-mailbox-send-identity
fix(composer): send from the address a message was delivered to
2026-09-07 22:38:51 +02:00
Linus Rath 049a1a1292 Merge pull request #663 from shukiv/fix/read-view-auto-direction
fix(rtl): auto-detect text direction in read, print and plain-text views
2026-09-07 22:36:25 +02:00
Linus Rath f349500546 fix: preserve task alarms that the edit dialog does not show #504 2026-09-07 22:34:47 +02:00
Linus Rath 80dadfbbd4 fix: open search hits from shared folders in the right account #923 2026-09-07 22:34:47 +02:00
Linus Rath 8477acf217 fix: keep the mobile actions panel below the status bar #936 2026-09-07 22:34:47 +02:00
Linus Rath d28d8dcd86 fix: report calendar clear failures instead of counting zero #434 2026-09-07 22:34:47 +02:00
Linus Rath f3f0127c9d fix: only show the unified mailbox section when it can be populated #843 2026-09-07 22:34:47 +02:00
Linus Rath 07bbde4786 fix: make the iCal subscription size limit configurable and show the real error #692 2026-09-07 22:34:47 +02:00
Linus Rath 8e4296ae5b fix: add the missing scheduled folder role label #495 2026-09-07 22:34:47 +02:00
Linus Rath 12416d9c47 fix: wire the x shortcut to thread expansion #683 2026-09-07 22:34:47 +02:00
Linus Rath f4d2fd950c fix: sort folders in the role assignment dropdown #984 2026-09-07 22:34:47 +02:00
Linus Rath c633ce1ff4 fix: keep the reading-mode toggle mounted so toolbar buttons stop jumping #964 2026-09-07 22:34:47 +02:00
Linus Rath ab4bf91b20 fix: let sender tables keep their own max-width #790 2026-09-07 22:34:47 +02:00
Linus Rath b85ba9603d fix: upload composer attachments through the composing identity's account #943 2026-09-07 22:34:47 +02:00
Linus Rath 0efde2e61d fix: set the answered flag when the reply is sent with a delay #985 2026-09-07 22:34:47 +02:00
Linus Rath 8dc1564b72 fix: archive shared-inbox mail into the owner's archive #889 2026-09-07 22:34:47 +02:00
Linus Rath 2b32a0110b fix: report a missing archive mailbox instead of failing silently #578 2026-09-07 22:34:47 +02:00
Shuki VakninandClaude Opus 5 e2990da554 fix(rtl): auto-detect direction in the thread view and .eml preview
The same missing dir="auto" as the read view, in the two other places
that build an email document.

thread-conversation-view builds a full document for each card's iframe
and its <body> had no direction, so a thread of right-to-left mail read
left-to-right in the one view that shows several messages at once.

eml-preview hands srcDoc a fragment rather than a document, so the
<body> is the browser's implicit one and cannot be annotated at all.
The wrapper the fragment already needs carries dir="auto" instead: a
<div> around sanitized HTML, and the existing <pre> for plain text.
Neither changes layout - the implicit body and its default margin stay
exactly as they were.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019KwXZEwxijHRbfobfXmcK2
2026-09-07 22:37:17 +03:00
Patrick RotterandClaude Opus 5 4fc7b8b50b fix(composer): send from the address a message was delivered to
On a shared, group or aliased mailbox every reply, reply-all and forward
went out as `identities[0]` - the account owner - whichever mailbox was
open. `autoSelectReplyIdentity` fused two behaviours: matching one of the
user's OWN identities, which never rewrites `From:`, and the domain
catch-all, which puts an address they have not configured into `From:`.
Only the first is safe for everyone, so it is now unconditional; the
rewrite stays behind the setting, which is what its description promises.
`findReplyIdentityId` already implemented that match and was referenced
only from tests.

`forward` is admitted to the match - it was excluded, so a forward from a
shared mailbox went out as the owner - but never takes the rewrite: a reply
continues a thread whose participants know the addressing, while a forward
introduces a rewritten From to a recipient the user just typed. Quick reply
matches own identities only, having no From row to show or correct a
rewrite, and now falls back to the primary's signature as the composer
does, so a shared-mailbox quick reply is still signed.

`findReplyIdentityId` now scans recipients in To, Cc, Bcc order rather than
scanning identities, and prefers an untagged identity over a differently
tagged sibling. Scanning identities let their order decide, and
`sortIdentities` puts the login's own address first - so `To: team@,
Cc: you@` replied as you, the case this is meant to fix.

Automatic selection is restricted to the active account: `composerClient`
follows the chosen identity, and a reply or forward still carries blobIds
only its own account's server can resolve. The dropdown still offers every
account's identities to pick by hand.

New messages are deliberately left gated: `composeFromAccountEmail` falls
back to `AccountEntry.email`, written once at first login, so resolving it
unconditionally would override a user-chosen default sender identity (#507).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 20:37:29 +02:00
Patrick RotterandClaude Opus 5 129f545aeb fix(pro): default the compose tab's From to the open mailbox
`ProComposeTabBody` rendered `<EmailComposer>` without
`composeFromAccountEmail`; only the standard shell in
`components/mail/mail-app.tsx` passed it, so `mode === 'compose'` resolved
`findComposeIdentityId(identities, undefined)` to null and every new message
in the Pro shell defaulted to the account owner even with a shared folder
open. That covered the whole compose surface there, since the Pro shell
hoists every "show composer" intent - `mailto:` links included - into a tab.

Resolved exactly as the standard shell does, so both share one rule, but
read once at mount: a tab body stays mounted while the tab lives, so
subscribing to the mailbox list would re-render the composer and its editor
on every counter refresh.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-07 20:36:44 +02:00
Shuki Vaknin 48048f165f fix(rtl): auto-detect text direction in read, print and plain-text views 2026-09-07 21:23:51 +03:00
Linus Rath c8edd1f2e1 Merge pull request #715 from lucletoffe/fix/unread-dot-alignment
fix(list): align the unread dot with the first line, not the row midpoint
2026-09-07 17:56:31 +02:00
Linus Rath 6a44442594 Merge pull request #953 from shukiv/fix/list-avatar-vertical-center
fix(list): centre the sender avatar against the row
2026-09-07 17:56:01 +02:00
Linus Rath ea49cc0d92 Merge pull request #968 from lucletoffe/fix/calendar-description-links
fix(calendar): linkify URLs in the event description
2026-09-07 17:55:32 +02:00
Linus Rath 949c6731ec Merge pull request #934 from dev-hive-kazniisa/feat/pwa-app-badge
feat(pwa): badge the installed app icon with unread count (Badging API)
2026-09-07 17:55:02 +02:00
Linus Rath 1122306ba1 Merge pull request #944 from shukiv/fix/rtl-mobile-drawer-side
fix(mobile): open the folder drawer from the right in RTL
2026-09-07 17:54:30 +02:00
Linus Rath adea2a5376 Merge pull request #945 from shukiv/feat/mobile-search-first-header
feat(mobile): search-first header, replacing the second toolbar row
2026-09-07 17:47:16 +02:00
Linus Rath 75585f224e Merge pull request #987 from ibayue/feature/composer-sticky-toolbar-font-size
feat(composer): sticky formatting toolbar with font-size and background color
2026-09-07 17:42:52 +02:00