A draft that carried attachments and no message re-opened with the
contents of one of the attachments as its text. Attach a .csv to an
empty draft, save it, re-open it: the editor shows the rows of the csv
as what you had written, and the next save or send makes that the real
message.
Both edit-draft paths built the text body by joining every value in
bodyValues:
Object.values(draft.bodyValues).map(v => v.value).join('\n')
bodyValues is keyed by part id, and getEmail asks for
fetchAllBodyValues, which per RFC 8621 4.1.4 returns a value for every
text/* part of the message - attachments included. So any attached
.csv, .txt, .log or .md was joined in as body text, and with no html
body to prefer it became the whole message.
Take the body from the parts the server lists as the body instead, and
from nothing else. A draft whose textBody is empty now re-opens empty,
which is what an attachments-only draft is.
The selection lives in lib/email-body-selection.ts beside
getRenderableHtmlBody, which exists because the viewer and the mobile
thread view had already drifted apart once (#489). mail-app and the pro
email tab held character-for-character copies of this join, so the same
drift was already in place.
Expanding a long attachment list made the composer unusable. With a few
dozen files, "+N" grew the chip row past the bottom of the composer: the
last rows were off-screen, the send toolbar went with them, and nothing
scrolled, so the only way out was to collapse the list again.
The row is a shrink-0 sibling of the body's scroll container, so every
pixel it takes comes out of the composer and out of nothing else, and it
has no scroller of its own. Collapsed that is fine - three chips and a
counter. Expanded, its height is the attachment count.
So bound it when it is expanded and let it scroll itself. 30vh keeps the
toolbar on screen on a laptop and still shows several rows; collapsed
behaviour is untouched, since three chips never needed a cap.
overscroll-contain stops a scroll that reaches the end of the list from
continuing into the message body behind it, which is the usual annoyance
once a small scroller appears next to a large one.