Summary
Mail.ru (and clients built on imap-codec, e.g. Himalaya via imap-next / email-lib) can fail to parse FETCH responses: the codec reports parse errors and downstream may skip entire messages, which shows up as an empty or incomplete envelope list even though the server has mail.
What we observed
-
Empty quoted string in addresses — Envelope address lists use ("" NIL "user" "domain") for an empty display name. RFC 3501 allows quoted to be empty (DQUOTE DQUOTE), but imap-codec’s quoted() parser did not accept zero characters between quotes (failure inside nom::escaped / take_while1).
-
body-fld-param with NIL value — Extension lists such as ("boundary" NIL) appear in BODYSTRUCTURE. Strict RFC expects string SP string pairs; some servers send NIL for the value. Parsing fails without a quirk (similar spirit to existing quirk_body_fld_enc_nil_to_empty).
-
Fixture / nesting — A real line uses multipart/mixed whose first part is multipart/alternative, so the BODYSTRUCTURE argument correctly begins with three ( after the keyword. Tests should reflect that shape so the full FETCH line parses end-to-end.
Proposed direction
- Fix
quoted() to accept "" (minimal, spec-aligned).
- Add a default
quirk feature (e.g. quirk_body_fld_param_nil_value) to treat NIL as an empty string for the second field in body-fld-param pairs when inside (...).
- Add regression tests: minimal
FETCH line for "" in addresses; optional integration test with a captured BODYSTRUCTURE line; targeted parsers for envelope vs body if useful for future bisection.
Happy to open a PR with this split (strict fix vs quirk) if that matches how you want to track server deviations.
Summary
Mail.ru (and clients built on imap-codec, e.g. Himalaya via imap-next / email-lib) can fail to parse
FETCHresponses: the codec reports parse errors and downstream may skip entire messages, which shows up as an empty or incomplete envelope list even though the server has mail.What we observed
Empty quoted string in addresses — Envelope address lists use
("" NIL "user" "domain")for an empty display name. RFC 3501 allowsquotedto be empty (DQUOTE DQUOTE), butimap-codec’squoted()parser did not accept zero characters between quotes (failure insidenom::escaped/take_while1).body-fld-paramwithNILvalue — Extension lists such as("boundary" NIL)appear inBODYSTRUCTURE. Strict RFC expectsstring SP stringpairs; some servers sendNILfor the value. Parsing fails without a quirk (similar spirit to existingquirk_body_fld_enc_nil_to_empty).Fixture / nesting — A real line uses
multipart/mixedwhose first part ismultipart/alternative, so theBODYSTRUCTUREargument correctly begins with three(after the keyword. Tests should reflect that shape so the fullFETCHline parses end-to-end.Proposed direction
quoted()to accept""(minimal, spec-aligned).quirkfeature (e.g.quirk_body_fld_param_nil_value) to treatNILas an empty string for the second field inbody-fld-parampairs when inside(...).FETCHline for""in addresses; optional integration test with a capturedBODYSTRUCTUREline; targeted parsers for envelope vs body if useful for future bisection.Happy to open a PR with this split (strict fix vs quirk) if that matches how you want to track server deviations.