Files
ElyOffice/tasks/reviews/C12.2-r1.md
T
ZacharyZhang-NYandClaude Opus 5.5 fe90221c11 C12.2: read and write MIME by the tree
The reader walks the MIME tree with its container context: alternative
picks versions, related finds its root by start, attached multiparts
stay whole, digest children are messages. Nesting deeper than 64
levels, counting enclosed messages, is refused, and over-deep parse
results are taken apart iteratively so dropping them cannot overflow
the stack. Composite parts with a Content-ID are cid targets.

The writer keeps attachment parameters and Content-IDs, writes
multipart and message attachments unencoded, and makes its own
Message-ID. SMTP adds BODY=8BITMIME for 8-bit bodies and SMTPUTF8
when any header block at any depth is 8-bit.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-19 17:35:05 -04:00

5.3 KiB

FAIL

  • crates/ely-mail-engine/src/mime.rs:198 — [P1] Text attachments lose their original file bytes. MessagePart::contents() returns charset-decoded UTF-8 for text/*, rather than just transfer-decoded octets. A text/plain; charset=iso-8859-1 attachment containing quoted-printable Caf=E9 becomes [67,97,102,195,169] instead of [67,97,102,233]. Building and reading a text/plain attachment with those original bytes instead produces [67,97,102,239,191,189]. Saving or forwarding therefore changes the file silently. Preserve attachment octets after transfer decoding; apply charset conversion separately to displayed bodies. Add non-UTF-8 text attachment tests; the existing every-byte test only covers application/octet-stream. Both failures are recorded in .work/C12.2-r1/probes.log.

  • crates/ely-mail-engine/src/mime.rs:104 — [P2] HTML body selection ignores multipart/related's start parameter. With type="text/html"; start="<root@example.com>", an image first and the HTML part with that Content-ID second, read returns html: None and puts both parts in inline. The actual message body is thus unavailable despite its explicit root declaration. Resolve the related root from start before choosing body parts, using the first child only when start is absent, as specified by RFC 2387 §3.2. Add this ordering to the MIME tests. Reproduced by a_related_html_root_can_come_after_its_image in the probe log.

  • crates/ely-mail-engine/src/mime.rs:81 — [P2] An attached multipart entity disappears as an attachment and its contents become the parent message's body. For an outer multipart/mixed containing plain body followed by multipart/alternative with Content-Disposition: attachment; filename=alternatives.mime, whose text child contains private attachment, read returns text: Some("body\nprivate attachment") and zero attachments. The parent's disposition applies to the whole multipart entity (RFC 2183 §2.9). Respect that disposition while traversing the MIME tree, retain the attached entity, and exclude its descendants from the main bodies. Add a regression for this structure; multipart_attachment_is_not_displayed_as_parent_body reproduces both incorrect outputs.

  • crates/ely-mail-engine/src/mime.rs:228 — [P2] Joining every body part concatenates mutually exclusive alternatives. A multipart/alternative with an ASCII plain-text version Cafe followed by its UTF-8 plain-text version Café yields Some("Cafe\nCafé"). The reader cannot subsequently select a representation because the alternatives and their container relationship have already been discarded. Select the supported alternative within each alternative container instead of joining its siblings; concatenation can remain for independent mixed body segments. RFC 2046 §5.1.4 specifies alternative selection. Add a same-type alternative regression; alternatives_of_the_same_type_are_not_concatenated fails in the probe log.

  • crates/ely-mail-engine/src/mime.rs:86 — [P2] A related image's attachment disposition prevents it from being exposed as a CID target. With an HTML root referencing cid:image@example.com and a related image carrying that Content-ID plus Content-Disposition: attachment, read returns an empty inline list and places the image only in attachments. Within a related object, disposition does not override the object's relationships (RFC 2387 §4). Determine CID resources using their MIME container context so this image remains available to the HTML body. Add coverage for a related resource with this disposition; related_cid_image_is_available_even_when_disposition_is_attachment reproduces the failure.

  • crates/ely-mail-engine/src/mime.rs:154 — [P2] Building attachments silently discards the supplied Part.content_id. An image attachment with content_id: Some("image@example.com") is written without any Content-ID header and reads back as None; HTML referencing that ID cannot resolve it. The supplied sample's PDF Content-ID is likewise lost, while the roundtrip test compares only name, type and bytes, concealing the loss behind the task's field-preservation claim. Serialize and validate the supplied Content-ID, and compare complete attachment metadata in the roundtrip test. Reproduced by supplied_attachment_content_id_survives_build in the probe log.

  • crates/ely-mail-engine/src/mime.rs:186 — [P2] The missing Content-Type default is wrong for children of multipart/digest. A digest containing an enclosed message with no explicit part Content-Type is parsed as a message by mail-parser, but leaf labels its bytes text/plain. Consumers therefore receive the wrong attachment type, and rebuilding from that metadata emits a text attachment instead of an attached message. The default in this container is message/rfc822 (RFC 2046 §5.1.5). Derive the effective type from the parent context or the parsed message variant, retaining text/plain for ordinary untyped parts. Add a digest regression; a_digest_child_defaults_to_message_rfc822 reproduces the mismatch.