You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
standard library email.parser fails to recognize multipart message #135854
If an email message with attachments contain a boundary with the characters "<--- ... --->" the email.parser module fails to recognize the message as being multipart.
I have attached to this bug report an example mailbox file, and when the following snippet is run on it you will see that is_multipart() returns False, although the message is clearly a multipart message.
I found this boundary string used in a real life email I received.
The surrounding angle brackets in <--- ... ---> are regarded as quotes and are removed by email.utils.unquote(str). The documentation also has a description of this.
So, email.parser treats the entire message as a single part when it fails to find the stripped boundary --- ... ---. However, if the angle appears on only one side of the boundary (not both), the parser can correctly detect the multi-part message.
Your observation that email.utils.unquote eats < makes sense.
I also observe this behavior in the From: field. If the "from" field in the message is given like "John Doe johndoe@example.com", msg["from"] will return"John Doe", however, if the "from" field in the message only contains "<johndoe@example.com>", msg["from"]` returns None.
I believe this behavior is also a bug. The module must return the fields from the message unaltered. When I generate a list of my mail messages, some of them have no sender, and that is not an appropriate behavior.
Hm, I can't reproduce it either now, but in my work with the module I am creating an sqlite3 database of all headers, and I can see the From: field is missing in cases where sender field in the mbox file only has a <....> construct. I will try to investigate further.
Since the 'From' issue hasn't been reproduced, we'll confine this issue to the boundary issue from the title.
The root of the problem is that utils.unquote is stripping <> "quotes". I have no idea why it is doing that, I can't see anywhere in the email library itself that that stripping would be appropriate. I can only conclude it is provided to facilitate stripping the <> off an addrspec (<a@b.com>), which as far as I can see the email library itself never uses utils.unquote to do.
Even if unquote wasn't stripping <>, the double unquoting could be an issue: imagine a boundary specified as "\"foo\"". But as I commented on the PR, simply removing the double quoting would make an invalid boundary specification valid, which doesn't seem like a good idea (unless other email clients do likewise?)
The best course I can see at the moment is to replace all the internal calls to unquote with calls to an internal function that does not strip <>, and apply the fix proposed in the PR as well. Unfortunately that could have backward incompatibility issues. Probably safe enough to do it in a feature release, though.
To clarify: <> are not valid parameter value "quoting" characters per RFC 2045, so they shouldn't be being stripped: such a value should be illegal for any mime parameter value, per the RFC.
Activity
tanloong commentedon Jun 23, 2025
Some findings:
The surrounding angle brackets in
<--- ... --->are regarded as quotes and are removed by email.utils.unquote(str). The documentation also has a description of this.So,
email.parsertreats the entire message as a single part when it fails to find the stripped boundary--- ... ---. However, if the angle appears on only one side of the boundary (not both), the parser can correctly detect the multi-part message.tanloong commentedon Jun 23, 2025
I think the boundary gets duplicate strippings. email.message.get_boundary() calls email.message.get_param() and utils.collapse_rfc2231_value() in sequence, both of the two functions perform their own stripping. The first stripping drops the double quotes, the second one drops the angle brackets.
mok0 commentedon Jun 24, 2025
Your observation that
email.utils.unquoteeats<makes sense.I also observe this behavior in the
From:field. If the "from" field in the message is given like "John Doe johndoe@example.com",msg["from"]will return"John Doe", however, if the "from" field in the message only contains "<johndoe@example.com>",msg["from"]` returns None.I believe this behavior is also a bug. The module must return the fields from the message unaltered. When I generate a list of my mail messages, some of them have no sender, and that is not an appropriate behavior.
tanloong commentedon Jun 25, 2025
@mok0 I can't reproduce it on my side, is there something I'm missing?
mok0 commentedon Jun 26, 2025
Hm, I can't reproduce it either now, but in my work with the module I am creating an sqlite3 database of all headers, and I can see the From: field is missing in cases where sender field in the mbox file only has a <....> construct. I will try to investigate further.
bitdancer commentedon Aug 19, 2026
Since the 'From' issue hasn't been reproduced, we'll confine this issue to the boundary issue from the title.
The root of the problem is that
utils.unquoteis stripping<>"quotes". I have no idea why it is doing that, I can't see anywhere in the email library itself that that stripping would be appropriate. I can only conclude it is provided to facilitate stripping the<>off an addrspec (<a@b.com>), which as far as I can see the email library itself never uses utils.unquote to do.Even if unquote wasn't stripping
<>, the double unquoting could be an issue: imagine a boundary specified as"\"foo\"". But as I commented on the PR, simply removing the double quoting would make an invalid boundary specification valid, which doesn't seem like a good idea (unless other email clients do likewise?)The best course I can see at the moment is to replace all the internal calls to unquote with calls to an internal function that does not strip
<>, and apply the fix proposed in the PR as well. Unfortunately that could have backward incompatibility issues. Probably safe enough to do it in a feature release, though.bitdancer commentedon Aug 19, 2026
To clarify:
<>are not valid parameter value "quoting" characters per RFC 2045, so they shouldn't be being stripped: such a value should be illegal for any mime parameter value, per the RFC.