Skip to content

feat(list): show attachments on list rows and open them from there - #947

Open
shukiv wants to merge 1 commit into
bulwarkmail:mainfrom
shukiv:feat/list-attachment-chips
Open

feat(list): show attachments on list rows and open them from there#947
shukiv wants to merge 1 commit into
bulwarkmail:mainfrom
shukiv:feat/list-attachment-chips

Conversation

@shukiv

@shukiv shukiv commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

Problem

A message with attachments shows a paperclip and nothing more. To reach a file you open the message, scroll past the body and find it in the attachment list — even when the file is the entire reason you opened the mail.

The rows could not do better than the paperclip: EMAIL_LIST_PROPERTIES requests hasAttachment, a boolean, so names and blobIds were never fetched.

Change

Request attachments alongside hasAttachment, and render the files as chips under the preview. Tapping one opens that file directly.

Chips route through the same path the viewer uses, so they honour the existing mailAttachmentAction setting — preview for previewable types, download otherwise — rather than introducing a second behaviour for the same action.

Inline parts are filtered out

This is the part worth reviewing. A single Outlook message routinely carries half a dozen cid: signature spacers under 200 bytes each; one real message I looked at had six of them plus one genuine PDF. Chipping all seven would bury the only file anyone wants.

realAttachments() keeps a part only when it is not disposition: "inline", not referenced by a Content-ID, and has a filename — the last because a part with no name can be neither labelled nor saved sensibly. Two chips are shown, the remainder collapse into a +N count.

Unified inbox

Downloads resolve the blob source from the row's own message rather than the selected one. In the unified inbox each row can belong to a different account, and the selected message may be from another account entirely, or there may be no selection at all.

Notes

  • Chips stop propagation on click and double-click, so opening a file never also opens the message.
  • Long names elide in the middle, keeping the extension, which is the identifying part.
  • tsc --noEmit clean. New unit tests cover the filtering rules; components/email and lib/jmap suites pass (132 tests).
  • Running on a production instance.

Cost

attachments is now fetched for every listed message. It is metadata only — no blob content — but it does add to each list fetch, so I would understand a preference for fetching it only when hasAttachment is true. That is not expressible in a single Email/get, which is why this asks for it uniformly; happy to change the approach if you would rather pay it differently.

A message with attachments showed a paperclip and nothing else, so the
only way to reach a file was to open the message, scroll to the bottom
and find it. The list rows never had the information to do better:
EMAIL_LIST_PROPERTIES asked for hasAttachment, a boolean.

Request attachments alongside it and render the files as chips under the
preview, each one opening that file directly. Chips honour the existing
mailAttachmentAction setting, so they preview or download exactly as the
viewer's attachment list does.

Inline parts are filtered out. A single Outlook message routinely carries
half a dozen cid: signature spacers of under 200 bytes; chipping those
would bury the one file the reader actually wants. Only parts that are
neither inline nor cid-referenced, and that carry a filename, are shown —
two at a time, with the remainder collapsed into a count.

Downloads resolve the blob source from the row's own message rather than
the selected one, so they stay correct in the unified inbox where each
row can belong to a different account.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant