`email.policy.compat32` does not work as `policy` for `email.message.MIMEPart`
Bug report
Bug description:
#!/usr/bin/python3
from email.message import MIMEPart
from email.policy import compat32
m = MIMEPart(policy=compat32)
m.set_content(b'\x00'*100, 'image', 'phg')
This raises the following exception:
Traceback (most recent call last):
File "[…]/test.py", line 7, in <module>
m.set_content(b'\x00'*100, 'image', 'phg')
~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/lib/python3.13/email/message.py", line 1136, in set_content
content_manager = self.policy.content_manager
^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'Compat32' object has no attribute 'content_manager'
This is with python3 3.13.3-1 on debian.
CPython versions tested on:
3.13
Operating systems tested on:
Linux
Linked PRs
- gh-143307
It's not entirely clear to me that this should work. (Or why you would want to do it.) MIMEPart is specifically part of the modern email API; compat32 is the legacy API.
Note that you can construct a MIMEPart with its default policy and then flatten it using compat32:
Python 3.13.2...
>>> from email.message import MIMEPart
>>> from email.policy import compat32
>>> m = MIMEPart()
>>> m.set_content(b'\x00'*100, 'image', 'phg')
>>> m.as_bytes(policy=compat32)
b'Content-Type: image/phg\nContent-Transfer-Encoding: base64\n\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==\n'
Perhaps the documentation for email.message.EmailMessage (which is shared by MIMEPart) should clarify the policy argument should not be a legacy Compat32 policy, and the documentation for email.policy.compat32 should clarify that it can be passed to a generator to flatten modern EmailMessage objects, but it cannot reliably be used to create them.
fwiw, it is not clear at all to me that some of these classes are deprecated and others are preferred, or that there is some pool of functions/methods/classes that will work together but that pool is disjoint from some other pool of other functions/classes/methods.
If there were clearer documentation about that distinction, i'd like to think i would have read it and avoided these particular concerns. And if there is such documentation, then perhaps the Exceptions raised could point directly at it for further clarity.
I would be happy to fix this issue. As mentioned earlier, I guess this is more of a content_manager policy incompatibility issue than an incompatibility with MIMEPart in general.
dkg: The table of contents for the email package docs clearly split the docs between the new API and the legacy API. It is true that if you read the docs without going through the index you don't get that information, though. So a general overhaul to add deprecation headers on the old API docs would be appropriate. I've been thinking of doing this as part of a general deprecation process for the old API, which (now that I'm active again as a core dev) I have plans for, but I want to clean up the open bugs against the new API first before I tackle that, which is going to take a while. So if someone wants to compare the new API docs to the old API docs and start working on a PR marking the things that weren't kept as deprecated, that would be great. But it should be a new issue.
As for the immediate issue, it is true that there was no intent that it be possible to specify compat32 as a policy for EmailMessage or MIMEPart. The bug fix would theoretically be to raise an error if someone tries, but that could be a backward compatibility issue. The errors you get when you do it pretty much speak for themselves, so I'd be inclined to make this a doc fix only, but we could also add a warning if someone does try to use compat32 with EmailMessage.
There was no intent that compat32 be used to serialize anything other than messages constructed with compat32. The biggest difference between the policies is how header folding is done. I don't wish to encourage anyone to serialize a non-compat32 message using the compat32 policy. While it might not produce any errors, I have a feeling (unverified) that the results won't actually be what one expects, or be particularly useful, for messages that have lines that exceed max_line_length. So maybe we should issue a warning for that as well?
I think the only doc change we really need is to add to the a line to the compat32 policy docs: The :const:compat32 policy should not be used as a policy for :class:~email.message.EmailMessage objects, and should only be used to serialize messages that were created using the :const:compat32 policy.`
@bitdancer
Hmm, you are right regarding this
While it might not produce any errors, I have a feeling (unverified) that the results won't actually be what one expects, or be particularly useful, for messages that have lines that exceed max_line_length.
Regarding the documentation change - I totally agree, but would you mind if we kept the two-way note? I mean also keeping the note in the EmailMessage doc:
The :class:`EmailMessage` class requires a policy that provides a
``content_manager`` attribute for content management methods like
:meth:`set_content` and :meth:`get_content` to work.
The legacy :class:`~email.policy.Compat32` policy does not support
these methods and should not be used with :class:`EmailMessage`.
I would prefer not to, it feels like it is just a distraction in the flow of the text. Maybe make it a footnote?
Moved it to the footnotes section. No news entry needed for such change, right?
Yes no need for a NEWS entry. If the skip news label is missing, ping me.
Thanks, hrimov.