Hi!
We’re running an API that among other tasks is supposed to send emails on behalf of the clients.
Sometimes we receive malformed address headers of the form To: test@test.de <test@test.de> (for whatever reason) and so far our approach has been to get rid of the malformed display name and normalize this to just the address part.
Until python-3.13.13 this was easy because python would just drop the realname, but this has changed in python-3.13.14:
> tox exec -e py31313-django52 -- python3
py31313-django52: commands[0]> python3
Python 3.13.13 (main, Jul 29 2026, 17:47:36) [GCC 15.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import email; import email.policy; m = email.message_from_string('To: test@test.de <test@test.de>\nFrom: obligatoryfrom@example.example\n\n', policy=email.policy.default); m['To']
'test@test.de'
>>>
py31313-django52: OK (3.03=setup[0.11]+cmd[2.92] seconds)
congratulations :) (3.05 seconds)
> tox exec -e py31314-django52 -- python3
py31314-django52: commands[0]> python3
Python 3.13.14 (main, Jul 30 2026, 13:33:37) [GCC 15.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import email; import email.policy; m = email.message_from_string('To: test@test.de <test@test.de>\nFrom: obligatoryfrom@example.example\n\n', policy=email.policy.default); m['To']
'test@test.de, <>'
>>>
py31314-django52: OK (2.97=setup[0.11]+cmd[2.86] seconds)
congratulations :) (3.00 seconds)
Python 3.13.14 (current version in openSUSE 16.0) splits the address into two addresses, the second is completely empty.
I can’t say I understand the reason behind this or if this is correct according to standards or not. Could anyone give an explanation or advice here?
In any case we would have the option of disallowing those kinds of addresses instead of trying to normalize them, as an uncoded @-sign in the realname part is clearly forbidden.
With a correctly encoded address-header, e.g. To: "test@test.de" <test@test.de> both python versions behave identically.
Python 3.11 and earlier (down to 3.6 I think) behave identical to 3.13.13.
I’d be grateful for any feedback
Best regards
Friedel