Skip to main content
← Back to Privacy GuideTutorials · 2026 Guide

What to Do About Python 3.15.2 Non-ASCII Email Errors?

Python 3.15 can raise an error when it cannot correctly flatten an address header containing a non-ASCII email address. This guide helps developers and QA teams isolate the address type, message policy, SMTP server support, and actual inbox result before choosing a fix.

The Python 3.15.2 release page dates the release to October 25, 2026. That release date does not mean every non-ASCII email fails: Python’s documented error applies when the generator cannot accurately flatten an address header containing a non-ASCII email address. First isolate serialization, then check whether the SMTP server supports SMTPUTF8, and finally verify receipt in a controlled inbox.

Who should read this: Python developers diagnosing address-header errors on Python 3.15.x.
QA engineers validating internationalized addresses in their own product.
Mail-system maintainers separating message-generation failures from SMTP rejection and actual delivery.

Last updated: November 1, 2026. Version and behavior references checked against the Python 3.15.2 release page, Python 3.15 documentation, and the linked protocol specification.

Start with the failure boundary, not the address label

A log line containing an accented display name is not proof that the display name caused the exception. A message can contain non-ASCII text in its subject or body, an internationalized display name, or a non-ASCII mailbox address. These are different inputs, and they do not fail at the same stage.

Python’s What’s New in Python 3.15 documents a generator error when an address header containing a non-ASCII email address cannot be accurately flattened. Do not broaden that statement into “Python 3.15 rejects all international email” or “any non-ASCII message body causes this error.” The address type, message policy, serialization path, and sending server all matter.

Record the exact exception and the operation that raised it. If the exception occurs during EmailMessage.as_bytes() or EmailMessage.as_string(), investigate message policy and header serialization first. If serialization completes and smtplib raises an error during sending, inspect SMTP capability negotiation. If the server accepts the message but no test inbox shows it, you have a delivery or acceptance-testing question—not a serialization diagnosis.

Preserve a minimal reproduction with the message fields and policy used by the failing code. Remove unrelated templates, attachments, and application logic. Keep the relevant address unchanged in a controlled test, but do not put real customer information into a bug report or shared test log.

Which address scenario is actually failing?

Treat the address as one of three separate test inputs: an ASCII mailbox with an internationalized display name, a mailbox whose address itself contains non-ASCII characters, or a message with non-ASCII content elsewhere. Reproduce each separately. The result helps show whether the issue is the address header or another part of message construction.

The display name contains non-ASCII characters

A display name such as “Zoë QA” is not the same thing as an internationalized mailbox address. The address can remain ASCII while the name contains Unicode:

from email.headerregistry import Address
from email.message import EmailMessage
from email.policy import SMTP

msg = EmailMessage(policy=SMTP)
msg["From"] = Address(
    display_name="Zoë QA",
    username="qa",
    domain="example.test",
)
msg["To"] = "recipient@example.test"
msg["Subject"] = "Header check"
msg.set_content("Test message")

wire_message = msg.as_bytes()

Here, the mailbox addresses are ASCII. The display name is not. Inspect the generated header bytes rather than inferring the cause from a log that prints the whole message as readable text. The Python email.message documentation describes message serialization; use the actual serialization result and exception from your environment as evidence.

If this case serializes successfully but the address-local-part case fails, the distinction is useful: a Unicode display name alone did not reproduce the address-header condition described in the Python 3.15 release notes. Keep the two tests separate in QA records. A template-level change to the display name would not necessarily fix a non-ASCII mailbox address.

The mailbox address itself contains non-ASCII characters

An internationalized email address may use non-ASCII characters in the local part. That is not interchangeable with an ASCII mailbox plus a Unicode display name. Use a reserved test domain and an address created for your own test system. Avoid copying a real user’s address into fixtures.

from email.headerregistry import Address
from email.message import EmailMessage
from email.policy import SMTP

msg = EmailMessage(policy=SMTP)
msg["From"] = "qa@example.test"
msg["To"] = Address(
    username="δοκιμή",
    domain="example.test",
)
msg["Subject"] = "EAI address test"
msg.set_content("Test message")

wire_message = msg.as_bytes()

This is a deliberately narrow reproduction: the recipient local part contains non-ASCII characters while the domain and other mailbox remain ASCII. If it fails during as_bytes(), capture that result before introducing an SMTP connection. If it serializes, that proves only that this construction succeeded under the selected policy. It does not prove that a receiving server can accept the address or that the message will arrive.

The Python email.policy documentation describes the EmailPolicy.utf8 option and the email.policy.SMTPUTF8 policy. The setting controls how the email package handles internationalized headers during serialization. It is not a capability negotiation with a remote mail server. In other words, changing a message policy cannot make an SMTP service support an extension it does not advertise.

Non-ASCII text appears only in the subject or body

Keep this as a control case. A Unicode subject or body is not evidence that the mailbox address is internationalized. If the control case succeeds while an address with a non-ASCII local part fails, focus on address parsing, the message policy, and the flattening operation.

Compare the same message under the policies actually used by the application. Do not switch policies only in a test snippet and then assume production uses the same one. Record the policy attached to the EmailMessage, the method that serializes it, and the relevant header values. If an application framework wraps message creation, reproduce its output as well as the smallest standard-library example.

What should you check when EmailMessage serialization fails?

Check the generation path before changing SMTP settings. The key question is whether the error happens while Python is flattening the message or later, while the application tries to send it. These are separate boundaries.

Use this sequence in a test environment you own or are authorized to use:

  • Capture the exception at its source. Record the exception class, message, stack location, Python version, and the exact method being called. Avoid logging credentials or real recipient data.
  • Reduce the message to headers and a short body. Remove attachments, template substitutions, and unrelated headers. Keep the address that triggers the failure.
  • Separate name from mailbox. Test a Unicode display name with an ASCII address, then test a non-ASCII mailbox local part with an ASCII display name.
  • Serialize before connecting to SMTP. Call the same serialization method your application uses. Save the resulting bytes for the test record when the message contains no private data.
  • Compare the selected policies. Check whether the message uses SMTP, SMTPUTF8, or a policy configured elsewhere in your application. Confirm the runtime policy rather than assuming it from a snippet.
  • Record the result for each input. Mark whether parsing, serialization, or sending failed. Do not summarize all failures as “email is broken.”
  • Repeat with the smallest production-equivalent path. If a framework or mail library constructs the message, run the test through that layer after the standard-library reproduction.

This method also answers the common question of what to inspect first after EmailMessage serialization fails: start with the exact address object and policy, then confirm that the failure reproduces without the SMTP connection. Changing the SMTP server configuration cannot repair an exception that occurs before the client opens a connection.

Important: A message that serializes successfully is not a delivery receipt. Keep serialization evidence and recipient-inbox evidence as separate test results.

Does Python SMTPUTF8 support mean the server will accept the message?

No. Python’s policy setting and the SMTP server’s advertised capability answer different questions. The policy affects email serialization. SMTPUTF8 is a server extension used to transfer internationalized addresses over SMTP. The RFC 6531 specification defines the SMTPUTF8 extension; the receiving SMTP service must support the extension for the sending client to use that path.

The smtplib documentation describes how SMTP.send_message handles internationalized addresses. When non-ASCII envelope addresses require SMTPUTF8, the method checks server support and can raise SMTPNotSupportedError if the server does not support the required extension. When supported, the send operation uses the SMTPUTF8 option and UTF-8 message serialization as needed. Verify this behavior against the Python version and SMTP implementation deployed by your application.

A minimal sending test might look like this:

import smtplib
from email.headerregistry import Address
from email.message import EmailMessage
from email.policy import SMTPUTF8

msg = EmailMessage(policy=SMTPUTF8)
msg["From"] = "qa@example.test"
msg["To"] = Address(
    username="δοκιμή",
    domain="example.test",
)
msg["Subject"] = "EAI delivery test"
msg.set_content("Test message")

with smtplib.SMTP("smtp.example.test", 587) as server:
    server.starttls()
    server.login("test-user", "test-password")
    server.send_message(msg)

Replace the host and credentials only with those of an authorized test service. Keep secrets out of source control and test output. This snippet illustrates the relevant policy and send call; it is not a guarantee that an arbitrary SMTP service supports SMTPUTF8.

Interpret the outcomes precisely:

  • A flattening exception before the connection points to message construction or serialization.
  • SMTPNotSupportedError indicates that the sending path requires SMTPUTF8 but the server does not support it.
  • A successful send_message call means the SMTP server accepted the message submission according to the response it returned. It does not prove final delivery.
  • A message visible in the controlled recipient inbox is evidence of receipt for that particular address, server path, and test run.

A server’s acceptance response and the mailbox’s receipt are different observations. Keep the SMTP response, message headers, and inbox result linked by a test identifier or timestamp in your own test record. Do not treat “sent” in an application log as equivalent to “received.”

Choose the next action by scenario

Use the result to select the next investigation, rather than applying one broad “enable UTF-8” fix:

  • Only the display name is non-ASCII: Inspect the generated header and the message policy. Keep the mailbox address ASCII in the control test. If serialization succeeds, investigate any later SMTP or delivery issue separately.
  • The mailbox local part is non-ASCII and serialization fails: Confirm the exact Python version, EmailPolicy.utf8 setting, and flattening method. Compare with the documented SMTPUTF8 policy. Reproduce against the version and dependencies used in production before changing application code.
  • Serialization succeeds but SMTP rejects the send: Check the server’s advertised SMTPUTF8 support and the exception from send_message. If the service lacks the extension, use a sending service that supports the required path or define a product fallback. Do not claim EAI support based only on local serialization.
  • The server accepts submission but the inbox is empty: Check the controlled mailbox, SMTP response, message headers, and any available delivery events. The current evidence establishes server acceptance, not actual receipt.
  • The product does not need internationalized mailbox addresses: Make that a deliberate, documented product constraint, and test the validation behavior. Do not silently accept an address that the sending path cannot handle.

The right fix depends on the project’s Python version, mail-library behavior, and sending service. Python 3.15.2’s release date is confirmed, but that date alone says nothing about whether a particular patch resolves a particular application failure. Check the official 3.15.2 release notes and current 3.15 documentation, then run the reproduction against the deployed environment. Limit any compatibility conclusion to the address types and mail path actually tested.

Verify receipt in a controlled inbox

A controlled inbox closes the gap between “the server accepted this submission” and “the test recipient received a readable message.” Use an inbox you control for tests of your own product or an environment where you have permission. Do not use customer addresses as test fixtures.

For each run, retain the address category, Python version, message policy, serialization result, SMTP response or exception, and inbox result. Inspect the received message’s relevant headers and body. If the message is absent, record that as a failed receipt check even if the SMTP submission returned successfully.

A disposable address can help isolate registration, notification, or verification-email tests from a developer’s primary inbox. It is still only a receiving endpoint: ordinary receipt does not establish that it supports a non-ASCII local part. Confirm address compatibility before using any test inbox for an EAI acceptance test. MXTemp can be considered as one controlled receiving option through the MXTemp inbox, but its general test-mailbox function should not be interpreted as a promise of SMTPUTF8 or internationalized-address support.

For test data hygiene, use addresses and message contents that do not contain real personal information. Review the MXTemp privacy policy before choosing any external test inbox for non-sensitive test messages. Do not send credentials, customer records, or production secrets to an inbox used only for compatibility checks.

After Python serialization and SMTP capability checks, a controlled inbox can provide the final receipt evidence for the specific path under test. It is one option for validating your own product’s email; it does not guarantee delivery or prove support for every internationalized address. For a temporary registration test or a single verification message, MXTemp offers an option that does not require exposing your primary inbox. Use it only after confirming that the address type and test data fit the service’s documented limits.

⚡Is the task definitely short-term and low risk?Open the prepared temporary inbox, copy the address, and keep the page open.Create a temporary email →↗Will you need order or security notifications later?Verify your real email first, then create a pauseable forwarding alias for this site.Use email forwarding →