IMAP API in Python: imaplib, IMAPClient, XOAUTH2 OAuth Guide (2026)

IMAP API Python Guide

IMAP API in Python: imaplib, IMAPClient & OAuth XOAUTH2 Guide

A complete guide to building Python IMAP email clients in 2026: from stdlib imaplib basics to IMAPClient production patterns, OAuth XOAUTH2 authentication for Gmail and Outlook, and when a unified email API saves you from the complexity entirely.

imap_client.py
import imaplib, email from email.header import decode_header # Connect with OAuth XOAUTH2 mail = imaplib.IMAP4_SSL('imap.gmail.com') auth_str = build_xoauth2(user, token) mail.authenticate('XOAUTH2', lambda x: auth_str) # Fetch unread messages mail.select('INBOX') _, ids = mail.search(None, 'UNSEEN') for uid in ids[0].split(): _, data = mail.fetch(uid, '(RFC822)') msg = email.message_from_bytes(data[0][1])
Fetching emails from Gmail, Outlook, IMAP...
Definition

What Is an IMAP Python Client?

An IMAP API Python client is any Python program that communicates with a mail server using the IMAP4 protocol (RFC 3501) to read, search, organize, and synchronize email messages. Unlike SMTP which only sends mail, IMAP gives your application bidirectional access to a remote mailbox: you can fetch headers, read bodies, set flags, move messages between folders, and listen for new arrivals in real time using IMAP IDLE.

Quick Definition

IMAP (Internet Message Access Protocol) is a standard protocol that lets clients retrieve and manage email stored on a remote server. A Python IMAP client connects over TLS port 993, authenticates (Basic or OAuth XOAUTH2), then issues IMAP commands to fetch, search, flag, and organize messages. Python provides three levels of abstraction: the standard library imaplib, the higher-level IMAPClient wrapper, and fully async options like aioimaplib. For a complete overview of IMAP architecture and use cases, see our IMAP API developer guide.

Email Sync for SaaS

Sync user inboxes into your CRM, ATS, or helpdesk. Python IMAP lets you poll or push (IDLE) new messages into your database without managing a full mail server.

Automation & AI Pipelines

Extract, classify, and route inbound emails using Python. Your IMAP client feeds a processing queue: invoice parsing, ticket creation, lead scoring, or LLM summarization.

Developer Tooling

Test email delivery, build inbox zero tools, or audit deliverability. Python IMAP gives you programmatic access to the same mailbox your users see. Check our email API guide for the full ecosystem.

Library Comparison

The 3 Python IMAP Stack Options

Choosing the right Python IMAP library depends on your use case: a quick script, a production service, or an async pipeline. Here is how the main options compare before we dive into code examples for each.

Library Type OAuth Support Async Parsing Helpers Best For
imaplib Stdlib (zero deps) Manual No Minimal Simple scripts, no external deps
IMAPClient Third-party wrapper Manual No Good Production IMAP without async
aioimaplib Async library Manual Yes Limited asyncio pipelines & IDLE at scale
Unipile APIBest Unified REST/SDK Built-in Yes Full Multi-provider production at scale
imaplib — Stdlib
OAuth:Manual setup
Async:No
Parsing:Minimal
Best for:Simple scripts, zero dependencies
IMAPClient — Wrapper
OAuth:Manual setup
Async:No
Parsing:Good helpers
Best for:Production IMAP, no async
aioimaplib — Async
OAuth:Manual setup
Async:Yes (asyncio)
Parsing:Limited
Best for:asyncio pipelines, IDLE at scale
Unipile APIBest
OAuth:Built-in
Async:Yes
Parsing:Full structured JSON
Best for:Multi-provider production at scale

Skip the IMAP complexity. Unipile abstracts imaplib, OAuth, and multi-provider logic into a single REST API. One integration for Gmail, Outlook, and any IMAP server.

Start building free
Code Tutorial

Quickstart: Connecting to IMAP with imaplib

The Python standard library ships with imaplib - no install needed. Here is a complete walkthrough from connection to body fetch, with honest commentary on where the pain points are.

1
Connect and authenticate

Use imaplib.IMAP4_SSL on port 993 for an encrypted connection. For Gmail and Outlook, see the server addresses in our IMAP server connection guide. Basic Auth (password) works for IMAP servers that still allow it - but Gmail and Outlook now require OAuth XOAUTH2 (covered in Section 5).

connect.py
import imaplib # Connect to Gmail IMAP (TLS port 993) mail = imaplib.IMAP4_SSL('imap.gmail.com', 993) # Basic auth (app password only - OAuth preferred) mail.login('user@gmail.com', 'app-password') # List all mailboxes status, mailboxes = mail.list() for box in mailboxes: print(box.decode('utf-8')) mail.logout()
2
Select a folder and search for messages

The select() call opens a mailbox and returns the message count. search() returns a space-separated byte string of message IDs - not UIDs. You need to decode and split manually.

search.py
# Select INBOX (or any folder) status, count = mail.select('INBOX') print(f'Messages: {count[0].decode()}') # Search UNSEEN messages status, msg_ids = mail.search(None, 'UNSEEN') ids = msg_ids[0].split() print(f'Unread count: {len(ids)}') # Search by sender _, from_ids = mail.search(None, 'FROM', 'boss@company.com') # Search by date range _, recent = mail.search(None, 'SINCE', '01-Jan-2026')
3
Fetch headers and parse the body

This is where imaplib gets messy. The raw response is a list of tuples containing bytes. You must index data[0][1] to reach the raw message, then pass it to the email module for parsing. Headers are RFC 2047-encoded and require decode_header().

fetch_body.py
import email from email.header import decode_header def decode_str(value): """Decode RFC 2047 encoded header value.""" parts = decode_header(value) decoded = [] for part, enc in parts: if isinstance(part, bytes): decoded.append(part.decode(enc or 'utf-8', errors='replace')) else: decoded.append(part) return ' '.join(decoded) for uid in ids[-5:]: # last 5 messages _, data = mail.fetch(uid, '(RFC822)') raw = data[0][1] # tuple unpacking pain msg = email.message_from_bytes(raw) subject = decode_str(msg['Subject'] or '') sender = decode_str(msg['From'] or '') # Walk MIME parts for plain text body if msg.is_multipart(): for part in msg.walk(): if part.get_content_type() == 'text/plain': body = part.get_payload(decode=True).decode('utf-8', errors='replace') print(f'From: {sender} | Subject: {subject}')

The imaplib pain points: raw byte responses require careful tuple indexing (data[0][1]), headers are RFC 2047-encoded and need decode_header(), multipart MIME bodies require a full walk(), and there are no built-in helpers for UIDs vs. sequence numbers. For production workloads, consider IMAPClient (Section 4) or a unified IMAP API instead.

Production Library

Going Further: IMAPClient for Production

Once you hit production with imaplib, you quickly notice its fragile response parsing, inconsistent UID handling, and absence of helpers for common tasks. IMAPClient is a Pythonic wrapper that smooths out these rough edges while staying close to the IMAP spec.

Why imaplib breaks in production
Responses are raw bytes tuples — fragile tuple indexing data[0][1]
No UID-based fetching by default (use uid() wrapper manually)
No built-in MIME parsing or body extraction helpers
IDLE requires manual socket management
RFC 2047 header decoding is your problem
What IMAPClient gives you
Structured dict responses - no tuple unpacking required
UID mode by default (use_uid=True)
Cleaner search(), fetch(), move(), copy() API
Built-in IDLE support with idle() / idle_check()
Works with any IMAP server - Gmail, Outlook, custom IMAP
imapclient_example.py
from imapclient import IMAPClient import pprint # Connect with IMAPClient (use_uid=True by default) server = IMAPClient('imap.gmail.com', ssl=True, use_uid=True) server.login('user@gmail.com', 'app-password') # Select and search server.select_folder('INBOX') messages = server.search(['UNSEEN']) print(f'{len(messages)} unread messages') # Fetch - returns structured dict, not raw bytes response = server.fetch(messages[:10], ['ENVELOPE', 'BODY[]', 'FLAGS']) for uid, data in response.items(): envelope = data[b'ENVELOPE'] print(f'UID {uid}: {envelope.subject}') # Move messages to folder server.move(messages[:5], 'Archive') # IDLE - wait for new messages (up to 29 min on Gmail) server.idle() responses = server.idle_check(timeout=60) print('IDLE response:', responses) server.idle_done() server.logout()

Even IMAPClient requires manual OAuth token management and multi-provider handling. Unipile abstracts all of this - OAuth refresh, provider quirks, IDLE reconnects - behind a single REST API. See our complete email API guide.

Build it with Unipile
OAuth XOAUTH2

OAuth XOAUTH2 in Python: Gmail and Microsoft 365

Basic password authentication is dead for major providers. Gmail has blocked it for standard accounts since May 2022. Microsoft 365 deprecated Basic Auth for IMAP in September 2024. XOAUTH2 (an OAuth 2.0 SASL mechanism) is now the only production-grade way to authenticate a Python IMAP client. For the full OAuth flow explanation, see our OAuth email API guide.

How XOAUTH2 works

XOAUTH2 is a SASL authentication mechanism that encodes an OAuth Bearer token into a base64 string with the format: user={email}\x01auth=Bearer {token}\x01\x01. This string is passed to imaplib.IMAP4_SSL.authenticate('XOAUTH2', callback). The callback returns the base64-encoded string. You are responsible for obtaining and refreshing the OAuth access token through Google or Microsoft identity endpoints before making the IMAP connection. For the Gmail scopes required, see our Gmail API scopes guide.

Gmail Gmail
Outlook Microsoft 365
gmail_xoauth2.py
import imaplib, base64, json from google.oauth2.credentials import Credentials from google.auth.transport.requests import Request def build_xoauth2_string(user_email, access_token): """Build XOAUTH2 SASL string for IMAP authentication.""" auth_string = f'user={user_email}\x01auth=Bearer {access_token}\x01\x01' return base64.b64encode(auth_string.encode('ascii')) def get_valid_token(creds_dict): """Refresh token if expired using google-auth library.""" creds = Credentials.from_authorized_user_info(creds_dict) if creds.expired and creds.refresh_token: creds.refresh(Request()) return creds.token # Required Gmail IMAP scope: https://mail.google.com/ user_email = 'user@gmail.com' access_token = get_valid_token(creds_dict) mail = imaplib.IMAP4_SSL('imap.gmail.com') auth_string = build_xoauth2_string(user_email, access_token) mail.authenticate('XOAUTH2', lambda x: auth_string) # Now use as normal mail.select('INBOX') _, ids = mail.search(None, 'ALL') print(f'Total messages: {len(ids[0].split())}')
Gmail scope requirement: The access token must be obtained with the https://mail.google.com/ scope (not gmail.readonly alone - that scope does not grant IMAP access). See our Gmail API scopes guide for a full breakdown. You also need to enable IMAP in Gmail settings and use a Google Cloud OAuth 2.0 client ID with the correct redirect URI.
outlook_xoauth2.py
import imaplib, base64 import msal def build_xoauth2_string(user_email, access_token): auth_string = f'user={user_email}\x01auth=Bearer {access_token}\x01\x01' return base64.b64encode(auth_string.encode('ascii')) # MSAL - Microsoft Authentication Library for Python CLIENT_ID = 'your-azure-app-client-id' TENANT_ID = 'your-tenant-id' # Scope for IMAP access (Outlook / Microsoft 365) SCOPE = ['https://outlook.office365.com/IMAP.AccessAsUser.All'] app = msal.PublicClientApplication(CLIENT_ID, authority=f'https://login.microsoftonline.com/{TENANT_ID}') # Acquire token (interactive or via refresh token) result = app.acquire_token_by_authorization_code(code, scopes=SCOPE, redirect_uri=redirect_uri) access_token = result['access_token'] # Connect to Outlook IMAP with XOAUTH2 user_email = 'user@outlook.com' mail = imaplib.IMAP4_SSL('outlook.office365.com') auth_string = build_xoauth2_string(user_email, access_token) mail.authenticate('XOAUTH2', lambda x: auth_string) mail.select('INBOX')
Microsoft 365 IMAP note: Since September 2024, Microsoft has disabled Basic Auth for IMAP on all Microsoft 365 tenants. You must use XOAUTH2. Register an Azure AD application, enable "IMAP.AccessAsUser.All" permission, and use MSAL for token acquisition. For Microsoft Graph as an alternative to IMAP, see our Microsoft Graph OAuth email guide.

OAuth XOAUTH2 is 50+ lines per provider. Unipile handles token refresh, XOAUTH2 handshake, and provider-specific quirks so your Python code stays focused on business logic - not auth plumbing.

Build your OAuth flow
Provider Matrix

Multi-Provider Reality Check

Every provider has its own authentication quirks, server addresses, and rate limits. Here is what your Python IMAP client needs to handle for each. For server hostnames and TLS port details, see our dedicated IMAP server connection guide.

Gmail logo
Gmail
imap.gmail.com:993
Auth:XOAUTH2 required
Scope:https://mail.google.com/
IDLE:Supported (29 min max)
Quirks:Gmail labels map to IMAP folders. Enable IMAP in settings.
Requires Google Cloud project with OAuth 2.0 client. See Gmail scopes guide for scope details.
Outlook logo
Outlook / Microsoft 365
outlook.office365.com:993
Auth:XOAUTH2 required
Scope:IMAP.AccessAsUser.All
IDLE:Supported
Quirks:Basic Auth disabled Sept 2024. Azure AD app + admin consent required for M365.
For REST-based alternative to IMAP, see Microsoft Graph OAuth email guide.
IMAP logo
Generic IMAP
your-server:993
Auth:Login/password OK
IDLE:Varies by server
Quirks:Server-specific folder naming, CAPABILITIES vary, some lack IDLE.
Examples:Fastmail, ProtonMail Bridge, Postfix/Dovecot self-hosted
Covers virtually any IMAP4rev1 server. See IMAP API guide for full list.
Yahoo Mail
imap.mail.yahoo.com:993
Auth:App password required (no XOAUTH2 for third-party)
IDLE:Supported
Yahoo dropped XOAUTH2 support for third-party apps. Generate an app-specific password in Yahoo Account Security settings.
iCloud Mail
imap.mail.me.com:993
Auth:App password required
IDLE:Supported
Two-Factor Authentication must be enabled on the Apple ID. Generate an app-specific password at appleid.apple.com.

Supporting multiple providers means maintaining separate auth flows, server configs, and quirk workarounds. Unipile normalizes Gmail, Outlook, and any IMAP server into a single API. Read our email API providers comparison for context.

Build multi-provider email
Unified API Alternative

When You Should Skip IMAP Entirely: Unified API Approach

After walking through imaplib, IMAPClient, and XOAUTH2, one truth becomes clear: raw IMAP in Python requires hundreds of lines of boilerplate for every provider you support. Unipile is a unified IMAP API that abstracts all of this into a single REST interface. You link user accounts (Gmail, Outlook, or any IMAP server) with OAuth, and Unipile handles every protocol detail on your behalf.

With raw imaplib (50+ lines per provider)
raw_imap.py
# 1. Get OAuth token (50+ lines) # 2. Build XOAUTH2 string # 3. Connect + authenticate # 4. Select folder # 5. Search messages # 6. Fetch raw bytes # 7. Parse tuple data[0][1] # 8. Decode RFC 2047 headers # 9. Walk MIME parts # 10. Handle attachments # 11. Manage IDLE timeouts # 12. Reconnect on error # 13. Repeat for Outlook... # 14. Repeat for IMAP servers...
With Unipile REST API (5 lines)
unipile_email.py
import requests # Fetch emails from any linked account r = requests.get( 'https://api6.unipile.com/api/v1/emails', headers={'X-API-KEY': api_key}, params={'account_id': account_id} ) emails = r.json()['items'] # Works for Gmail, Outlook, any IMAP
OAuth handled for you

Unipile manages XOAUTH2 token acquisition, refresh, and expiry for Gmail and Outlook. No MSAL or google-auth setup needed in your code.

Normalized JSON responses

No raw bytes, no tuple unpacking, no RFC 2047 decoding. Every email comes back as clean structured JSON with parsed headers, body, and attachments.

Real-time webhooks

Instead of managing IDLE sessions and reconnects, Unipile pushes new email events to your webhook endpoint. No polling, no socket management.

Multi-provider by default

One API endpoint serves Gmail, Outlook, and any IMAP server. Add new providers by linking accounts - no code changes required on your side.

Send emails too

Unipile covers the full email lifecycle. Read, search, move, flag, and send - all from the same API. See our Python send email guide for the sending side.

Per-user linked accounts

Each of your users links their own account via OAuth. Unipile acts as an independent technical intermediary on behalf of each authenticated user - not a shared credential pool.

Production Pitfalls

Common Pitfalls in Production

After getting a Python IMAP client working locally, production reveals edge cases that can cause silent data loss, connection drops, or broken character encoding. Here are the most common issues and how to fix them.

2026 Breaking Change: Microsoft Basic Auth IMAP End-of-Life

Microsoft completed the removal of Basic Authentication for IMAP on all Microsoft 365 tenants in September 2024. Any Python code using mail.login(user, password) against outlook.office365.com will now receive AUTHENTICATE failed. Migration to XOAUTH2 (Section 5) is mandatory for all Microsoft 365 / Outlook IMAP integrations. Exchange on-premises deployments may still support Basic Auth depending on server configuration.

01
IMAP IDLE timeout (29 minutes on Gmail)

Gmail silently terminates IDLE connections after approximately 29 minutes. If your code does not renew the IDLE session, new messages stop arriving without any exception being raised.

Fix: Set a timer to idle_done() every 25 minutes, then immediately call idle() again. Use select_folder('INBOX', readonly=False) to recheck message count on reconnect.
02
RFC 2047 charset decoding errors

Email headers like Subject and From use RFC 2047 encoding (=?UTF-8?B?...?=). Calling str(msg['Subject']) directly on a bytes value returns garbage or raises UnicodeDecodeError.

Fix: Always use email.header.decode_header() and handle each part's encoding explicitly. Pass errors='replace' to .decode() to avoid crashes on malformed headers.
03
Attachment parsing from multipart messages

Attachments live in nested MIME parts. Calling get_payload() on a multipart message returns a list of parts, not the content. Inline images are Content-Disposition: inline and have a Content-ID.

Fix: Walk all parts with msg.walk(), check get_content_disposition() for attachment, and call get_payload(decode=True) on attachment parts to get decoded bytes.
04
Connection pooling and thread safety

imaplib.IMAP4_SSL instances are NOT thread-safe. Using one connection across multiple threads causes garbled responses. Creating a new connection per request is expensive and rate-limited.

Fix: Use a connection pool (one connection per worker thread) or an async library like aioimaplib. Always implement exponential backoff for reconnect attempts after IMAP4.abort exceptions.
05
Rate limits and quota exhaustion

Gmail limits IMAP connections to 15 concurrent connections per account and enforces bandwidth quotas (2,500 MB/day via IMAP). Fetching entire RFC822 bodies at scale will hit these limits quickly.

Fix: Fetch headers first (RFC822.HEADER), then fetch bodies selectively. Use BODY.PEEK[] instead of RFC822 to avoid auto-marking as read. Implement exponential backoff on [OVERQUOTA] responses.
06
OAuth token expiry mid-session

Access tokens from Google and Microsoft expire after 3,600 seconds (1 hour). If your IMAP session is still open when the token expires, the next command after expiry will silently fail or return NO.

Fix: Track the expires_at timestamp. Before each batch operation, check if the token is within 5 minutes of expiry and refresh proactively. Store refresh tokens securely. This is exactly what Unipile handles automatically.

Avoiding all 6 pitfalls requires significant infrastructure. Unipile handles IDLE reconnects, token refresh, rate limiting, and multi-provider normalization - so you can focus on your product logic. Part of our full email API guide.

Build without the pitfalls
FAQ

Frequently Asked Questions

Common questions about Python IMAP clients, imaplib, IMAPClient, XOAUTH2 authentication, and when to use a unified email API instead.

01
What is the best Python IMAP library?
For simple scripts, imaplib from the standard library is sufficient with zero dependencies. For production use, IMAPClient provides a cleaner API with structured responses and built-in IDLE support. For async workloads at scale, aioimaplib integrates with asyncio. If you need multi-provider support (Gmail, Outlook, and custom IMAP servers) with OAuth handled automatically, a unified IMAP API like Unipile removes most of the complexity.
02
Can imaplib read Gmail emails in Python?
Yes. Connect to imap.gmail.com on port 993 using imaplib.IMAP4_SSL. However, Gmail no longer accepts plain username/password login for third-party apps. You must use OAuth XOAUTH2 authentication with an access token obtained from Google using the https://mail.google.com/ scope. See our Gmail API scopes guide for the full scope breakdown. App passwords still work for personal accounts with 2-step verification enabled, but OAuth is required for applications.
03
What is XOAUTH2 in Python?
XOAUTH2 is a SASL (Simple Authentication and Security Layer) mechanism used to authenticate IMAP connections with an OAuth 2.0 Bearer token instead of a password. In Python, you encode the string user={email}\x01auth=Bearer {token}\x01\x01 in base64, then pass it to imaplib.IMAP4_SSL.authenticate('XOAUTH2', callback). This replaces the deprecated Basic Auth login for Gmail and Microsoft 365. Full implementation examples are in Section 5 of this guide. See also our OAuth email API guide.
04
How do I use OAuth with imaplib?
To use OAuth with imaplib: 1) Obtain an access token from the provider (Google OAuth 2.0 or Microsoft MSAL). 2) Build the XOAUTH2 string: base64(f'user={email}\x01auth=Bearer {token}\x01\x01'). 3) Call mail.authenticate('XOAUTH2', lambda x: auth_string). For Gmail, use the google-auth library to manage token refresh. For Outlook/Microsoft 365, use the msal Python library. Both require registering an OAuth application in Google Cloud Console or Azure AD. The full imap python oauth code is in Section 5 above.
05
imaplib vs IMAPClient - which one should I use?
Use imaplib when you need zero external dependencies or only a simple one-off script. Use IMAPClient for production code: it returns structured dictionaries instead of raw byte tuples, uses UIDs by default, provides cleaner search()/fetch()/move() methods, and includes built-in IDLE support. Both require you to handle OAuth token management yourself. Neither is async - for asyncio-based pipelines, consider aioimaplib. Install IMAPClient with pip install imapclient.
06
How do I read Outlook emails with Python IMAP?
Connect to outlook.office365.com on port 993 using imaplib.IMAP4_SSL. Since September 2024, Basic Auth is disabled for Microsoft 365 - you must use XOAUTH2. Register an Azure AD application, request the IMAP.AccessAsUser.All permission, obtain an access token using the msal Python library, then authenticate with mail.authenticate('XOAUTH2', ...). For personal Outlook.com accounts, the same OAuth flow applies. For server details and TLS configuration, see our IMAP server connection guide.
07
Does IMAP work with Microsoft 365?
Yes, Microsoft 365 supports IMAP at outlook.office365.com:993. However, since September 2024, Microsoft has fully disabled Basic Authentication for IMAP on Microsoft 365 tenants. You must use OAuth 2.0 with the XOAUTH2 SASL mechanism. Your Azure AD administrator may also need to enable IMAP access in the Exchange admin center. An alternative is to use the Microsoft Graph API (REST) which avoids IMAP entirely and provides richer metadata.
08
How do I handle IMAP IDLE in Python?
IMAP IDLE lets the server push notifications when new messages arrive. With IMAPClient: call server.idle() to enter IDLE mode, then server.idle_check(timeout=60) to wait for events. Gmail silently disconnects after ~29 minutes, so you must renew: call server.idle_done() every 25 minutes, then server.idle() again. With raw imaplib, IDLE requires manual socket-level management - considerably more complex. For production real-time email, a webhook-based approach (as Unipile provides) is more reliable than maintaining IDLE sessions.
09
Can I use async IMAP in Python?
Yes. The aioimaplib library provides an asyncio-compatible IMAP4 client for Python. It supports standard IMAP commands and IDLE in an async context, making it suitable for high-concurrency pipelines where you manage many mailboxes simultaneously. However, aioimaplib has a smaller community than imaplib or IMAPClient, and OAuth support still requires manual XOAUTH2 implementation. For teams prioritizing developer speed over fine-grained control, a REST-based unified API delivers real-time email via webhooks without async socket management.
10
How does Unipile compare to imaplib for email integration?
imaplib is a low-level Python standard library requiring 50-200 lines per provider: OAuth token management, XOAUTH2 construction, raw bytes parsing, RFC 2047 header decoding, MIME body walking, IDLE reconnect loops. Unipile is a unified REST API that abstracts all of that into a single HTTP call with normalized JSON responses, built-in OAuth for Gmail and Outlook, webhook delivery for new emails, and multi-provider support. The trade-off: Unipile is a managed service with its own pricing, while imaplib is free but requires significant infrastructure investment. See our full IMAP API guide and provider comparison.

Still have questions about IMAP API in Python? Our team can help you choose the right approach for your use case - raw IMAP or unified API.

Talk to an expert
en_USEN