MimePart: do not quote a display name that is MIME-encoded - #106
Open
hubipe wants to merge 1 commit into
Open
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
encodeSequence()wrapped a display name in aquoted-stringbefore handing it toiconv_mime_encode(), so the quotes ended up inside the base64 payload of the encoded-word. Clients decode them as literal characters, and every name containing diacritics reached the recipient with visible quotation marks around it:Quoting is also unnecessary on that path. An encoded-word is built from
=?, the charset token and base64 characters, all of which are safe inside aphrase; the original dots, commas, parentheses and quotes cannot break the header once they are encoded. RFC 2047 §5 puts it the other way round: anencoded-wordmust not appear within aquoted-string.Solution
Drop the
$escape()call on the encoded-word branch. The same call on the literal branch stays – there the name really is emitted as-is, and characters outsideatextdo need aquoted-string.SequenceValue(RFC 2231Content-Dispositionfilenames) is untouched – there the quotes are added after encoding, i.e. outside the encoded text, which is what that grammar requires.Changed test expectations
Four existing tests asserted the old bytes, so their expectations are updated. Every new value decodes back to exactly the name that was passed in – verified with
iconv_mime_decode():Mail.email.phpt"Žluťoučký kůň"→Žluťoučký kůňMail.email.phpt"Žluťoučký \"kůň\""→Žluťoučký "kůň"Mail.email.multiple.phpt,Mail.longLines.phpt"Řehoř Řízek"→Řehoř Řízek,"Luboš Smažák"→Luboš SmažákMail.headers.002.phpt"Kdo uteče, obědvá"→Kdo uteče, obědváTwo of those deserve a note, because they look like the cases the quoting was meant to protect:
Žluťoučký "kůň"– the quotes the caller supplied were previously backslash-escaped and the escapes were base64-encoded, so the recipient saw"Žluťoučký \"kůň\"". They now survive verbatim.Kdo uteče, obědvá– the comma is inside the base64 payload, so it cannot be read as an address separator.Mail.headers.002.phptnow asserts this explicitly.tests/Mail/Mail.email.encodedName.phptis added as a regression test, covering both paths: an ASCII name outsideatextstill becomes a realquoted-string, an encoded name carries no quotes, caller-supplied quotes round-trip, and a comma in an encoded name does not split the address list.docs/internals.mdgains a bullet on why the quoting belongs to the literal path only.Compatibility
No API or behaviour change for callers –
getFrom()etc. already returned the unquoted name, this only makes the wire format agree with it. What does change is the encoded bytes of any non-ASCII display name, so anything asserting header bytes verbatim (as the four tests above did) will need updating. Worth deciding whether this lands on master or a patch branch.Verification
All four CI jobs run locally on PHP 8.4: