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>
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 fortext/*, rather than just transfer-decoded octets. Atext/plain; charset=iso-8859-1attachment containing quoted-printableCaf=E9becomes[67,97,102,195,169]instead of[67,97,102,233]. Building and reading atext/plainattachment 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 coversapplication/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'sstartparameter. Withtype="text/html"; start="<root@example.com>", an image first and the HTML part with that Content-ID second,readreturnshtml: Noneand puts both parts ininline. The actual message body is thus unavailable despite its explicit root declaration. Resolve the related root fromstartbefore choosing body parts, using the first child only whenstartis absent, as specified by RFC 2387 §3.2. Add this ordering to the MIME tests. Reproduced bya_related_html_root_can_come_after_its_imagein 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/mixedcontaining plainbodyfollowed bymultipart/alternativewithContent-Disposition: attachment; filename=alternatives.mime, whose text child containsprivate attachment,readreturnstext: 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_bodyreproduces both incorrect outputs. -
crates/ely-mail-engine/src/mime.rs:228 — [P2] Joining every body part concatenates mutually exclusive alternatives. A
multipart/alternativewith an ASCII plain-text versionCafefollowed by its UTF-8 plain-text versionCaféyieldsSome("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_concatenatedfails in the probe log. -
crates/ely-mail-engine/src/mime.rs:86 — [P2] A related image's
attachmentdisposition prevents it from being exposed as a CID target. With an HTML root referencingcid:image@example.comand a related image carrying that Content-ID plusContent-Disposition: attachment,readreturns an emptyinlinelist and places the image only inattachments. 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_attachmentreproduces the failure. -
crates/ely-mail-engine/src/mime.rs:154 — [P2] Building attachments silently discards the supplied
Part.content_id. An image attachment withcontent_id: Some("image@example.com")is written without any Content-ID header and reads back asNone; 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 bysupplied_attachment_content_id_survives_buildin 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, butleaflabels its bytestext/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 ismessage/rfc822(RFC 2046 §5.1.5). Derive the effective type from the parent context or the parsed message variant, retainingtext/plainfor ordinary untyped parts. Add a digest regression;a_digest_child_defaults_to_message_rfc822reproduces the mismatch.