Skip to content

fix(msg): RFC 2047 encode non-ASCII names in address headers#317

Open
lukas-r wants to merge 1 commit into
sabuhish:masterfrom
lukas-r:fix/rfc2047-recipient-headers
Open

fix(msg): RFC 2047 encode non-ASCII names in address headers#317
lukas-r wants to merge 1 commit into
sabuhish:masterfrom
lukas-r:fix/rfc2047-recipient-headers

Conversation

@lukas-r
Copy link
Copy Markdown

@lukas-r lukas-r commented May 13, 2026

What

Encode non-ASCII display names in recipient headers (To, Cc, Bcc, Reply-To, From) via email.utils.formataddr(..., charset="utf-8") so they are RFC 2047 quoted-printable on the wire instead of raw UTF-8. ASCII names are unaffected — formataddr only escapes when needed, so existing tests pass unchanged.

Reason

Fixes #316 (and addresses the root cause of #225).

str(NameEmail("Lukas Böhm", "lboehm@example.com")) returns 'Lukas Böhm <lboehm@example.com>' — raw UTF-8. Older Python versions silently re-encoded such headers; Python 3.14 no longer does. Office 365's SMTP submission server then strips the non-ASCII bytes from the recipient and rejects the message with:

550 5.2.254 InvalidRecipientsException; Sender throttled due to continuous invalid recipients errors.
Recipient 'Lukas Bhm <lboehm@example.com>' is not resolved.

Repeated failures push the sender mailbox into a throttled state.

formataddr(("Lukas Böhm", "lboehm@example.com"), charset="utf-8") returns '=?utf-8?q?Lukas_B=C3=B6hm?= <lboehm@example.com>' — RFC 2047 compliant, ASCII-clean.

The same charset="utf-8" is also added to the existing formataddr call in FastMail._sender so MAIL_FROM_NAME gets the same protection.

Test

New test_non_ascii_names_are_rfc2047_encoded in tests/test_message.py asserts that headers for umlaut/diacritic names are ASCII-encodable, contain =?utf-8? MIME markers, and round-trip back to the original Unicode via decode_header + getaddresses.

All 24 tests pass on Python 3.14.

str(NameEmail) emits the display name as raw UTF-8, so To/Cc/Bcc/
Reply-To headers built via ", ".join(str(r) for r in ...) carry raw
non-ASCII bytes. On older Python versions the stdlib email package
silently re-encoded these (issue sabuhish#225); on Python 3.14+ it no longer
does, and some SMTP servers (e.g. Office 365) strip the non-ASCII
bytes from the recipient display name and reject the message with
`550 5.2.254 InvalidRecipientsException`, eventually throttling
the sender.

Use email.utils.formataddr with charset="utf-8" so display names
are RFC 2047 quoted-printable encoded. ASCII names round-trip
unchanged.

Also pass charset="utf-8" to the existing formataddr call in
FastMail._sender so MAIL_FROM_NAME has the same protection.

Fixes sabuhish#316
Refs sabuhish#225
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

To: / Cc: / Bcc: headers emit raw UTF-8 instead of RFC 2047 (5.2.254 InvalidRecipientsException with Office 365 on Python 3.14)

1 participant