WSS
Web Specification Studio Home
On this page
InternationalisationRecommendedUpdated

Internationalized Email Addresses (EAI) & Punycode

Support Internationalized Domain Names (IDN) via Punycode and handle non-ASCII local-parts using RFC 6530 Email Address Internationalization (EAI) and SMTPUTF8.

What it is

Email Address Internationalization (EAI), standardized across RFC 6530, RFC 6531, and RFC 6532, extends SMTP and email address syntax to allow non-ASCII Unicode characters in both the domain name (e.g., @münchen.de or @中国.cn) and the local-part (e.g., pelé@example.com or 用户@domain.com).

Handling internationalized addresses involves two core technical mechanisms:

  1. Internationalized Domain Names (IDN / Punycode): Translates Unicode domain names into ASCII-compatible encoding prefixed with xn-- (e.g., münchen.de -> xn--mnchen-3ya.de) for traditional DNS lookups.
  2. SMTPUTF8 Protocol Extension (RFC 6531): Enables MTAs to negotiate transmission of raw UTF-8 characters across the entire SMTP envelope (MAIL FROM, RCPT TO) and RFC 5322 header section.
EHLO mail.example.com
250-mx.google.com at your service
250-SIZE 35882577
250-8BITMIME
250-SMTPUTF8
MAIL FROM:<[email protected]> SMTPUTF8
250 2.1.0 OK
RCPT TO:<pelé@xn--mnchen-3ya.de>
250 2.1.5 OK

Why it matters

  • Global Inclusivity for Non-Latin Alphabets: Over 3 billion people communicate in writing systems other than the Latin alphabet (Chinese, Devanagari, Cyrillic, Arabic). Rejecting user registration because their email address contains characters like ü, ñ, or alienates global customers.
  • DNS Resolution Compatibility: DNS root servers and standard resolver libraries only query ASCII labels. If your email dispatch system attempts to resolve MX records for münchen.de without converting it to xn--mnchen-3ya.de, the lookup returns NXDOMAIN and delivery fails immediately.
  • Transport Failure Prevention: Sending raw non-ASCII local-parts to receiving MTAs that do not support SMTPUTF8 results in immediate connection aborts or 501 Syntax error in parameters rejections.

How to implement

1. Convert Internationalized Domain Names (IDN) to Punycode at DNS Resolution: When querying MX, A, or AAAA records, convert the domain portion to Punycode using the idna standard (RFC 5890):

import punycode from "punycode/";

function normalizeEmailAddress(email: string): string {
  const [localPart, domainPart] = email.split("@");
  if (!domainPart) return email;

  // Convert domain from Unicode to Punycode (e.g., münchen.de -> xn--mnchen-3ya.de)
  const asciiDomain = punycode.toASCII(domainPart.toLowerCase());
  return `${localPart}@${asciiDomain}`;
}

2. Verify SMTPUTF8 Extension Support During the SMTP Handshake: When connecting to a destination mail transfer agent:

  1. Issue EHLO <hostname>.
  2. Inspect the 250 capability lines for the SMTPUTF8 keyword.
  3. If SMTPUTF8 is advertised, include the SMTPUTF8 parameter in the MAIL FROM: command:
    MAIL FROM:<[email protected]> SMTPUTF8
  4. If SMTPUTF8 is not supported and the recipient local-part contains non-ASCII characters, handle the delivery failure gracefully or route through an internationalized gateway.

3. Normalize Unicode Strings with NFC (Canonical Decomposition, followed by Canonical Composition): Apply Unicode Normalization Form C (NFC) to all email addresses at ingestion. This ensures that composite characters (e.g., é represented as single code point \u00E9 vs e + combining acute \u0065\u0301) match identically in database queries.

Common mistakes

  • Rejecting Valid Non-ASCII Emails with Outdated Regex: Using restrictive ASCII-only regex patterns (such as /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/) in form validation that reject valid European and international characters.
  • Attempting Punycode on the Local-Part: Punycode is designed exclusively for the domain portion. Encoding the local-part with xn-- produces an invalid, non-existent address.
  • Omitting the SMTPUTF8 Parameter on the Wire: Sending raw UTF-8 local-parts without adding the SMTPUTF8 parameter to the MAIL FROM: command, violating RFC 6531.
  • Case-Folding Differences in Non-Latin Alphabets: Assuming standard English uppercase/lowercase rules apply to Turkish (I / ı, İ / i) or German (ß / SS).

Verification

1. Validate IDN to Punycode conversion in test suite:

python3 -c "
import idna
domain = 'münchen.de'
punycode_domain = idna.encode(domain).decode('ascii')
print('Punycode:', punycode_domain)
# Output: xn--mnchen-3ya.de
"

2. Query MX records for Punycode domains:

dig +short MX xn--mnchen-3ya.de

3. Inspect SMTP handshake with swaks:

swaks --to pelé@example.com --from [email protected] --server mail.example.com --ehlo test.com --smtputf8

Related topics

Sources & further reading