The problem

At work, I recently had to automatically create and send out emails. My tool of choice for this has been Python, which has a nice email module directly in the standard library.

python-email-header-encoding/broken_code.py
1
2
3
4
5
from email.message import EmailMessage

msg = EmailMessage()
msg['Subject'] = '"Michael Müller" <mm@example.org>'
# -> Will be rejected by the mailserver on sending

Unfortunately, I hit multiple problems when trying to send messages to a receipient who's name contained non-ASCII characters.

Problem 1: The mailserver rejected the email, as headers were invalid.

To solve this, the Python docs mention the Header class, which can be used to properly encode email headers before sending out.

python-email-header-encoding/header_class_raw.py
1
2
3
4
5
from email.header import Header
from email.message import EmailMessage

msg = EmailMessage()
msg['Subject'] = Header('"Michael Müller" <mm@example.org>', 'utf-8')

Problem 2: Unfortunately, the example in the documentation is wrong and causes a bug, which has already been reported 3 years ago.

python-email-header-encoding/error.txt
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
Traceback (most recent call last):
  File "header_class_raw.py", line 5, in <module>
    msg['Subject'] = Header('"Michael Müller" <mm@example.org>', 'utf-8')
    ~~~^^^^^^^^^^^
  File "cpython@3.13.2/lib/python3.13/email/message.py", line 441, in __setitem__
    self._headers.append(self.policy.header_store_parse(name, val))
                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^
  File "cpython@3.13.2/lib/python3.13/email/policy.py", line 148, in header_store_parse
    return (name, self.header_factory(name, value))
                  ~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
  File "cpython@3.13.2/lib/python3.13/email/headerregistry.py", line 604, in __call__
    return self[name](name, value)
           ~~~~~~~~~~^^^^^^^^^^^^^
  File "cpython@3.13.2/lib/python3.13/email/headerregistry.py", line 192, in __new__
    cls.parse(value, kwds)
    ~~~~~~~~~^^^^^^^^^^^^^
  File "cpython@3.13.2/lib/python3.13/email/headerregistry.py", line 267, in parse
    kwds['parse_tree'] = cls.value_parser(value)
                         ~~~~~~~~~~~~~~~~^^^^^^^
  File "cpython@3.13.2/lib/python3.13/email/_header_value_parser.py", line 1130, in get_unstructured
    if value[0] in WSP:
       ~~~~~^^^
TypeError: 'Header' object is not subscriptable

The solution

While the issue linked above mentions workarounds in the comments, none have worked for me.

After fiddling around a bit, I was able to solve the issue using the following approach:

python-email-header-encoding/working_headers.py
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
from email.header import Header
from email.message import EmailMessage

msg = EmailMessage()
msg['Subject'] = Header(
    '"Michael Müller" <mm@example.org>',
    'utf-8'
).encode(maxlinelen=9999)

print(msg.as_string())
# Outputs:
#   Subject: "Michael =?utf-8?q?M=C3=BCller=22?= <mm@example.org>

By explicitly encoding the header, I was able to pass it successfully to the mailserver. Note that the maxlinelen is required to prevent any newlines into the value, which causes another crash.