How to Read Emails via API: A Developer’s Guide to Inbox Access (2026)

Developer Guide 2026

How to Read Emails via API: A Developer's Guide to Inbox Access

Scope: This guide covers sync APIs for reading users' existing inboxes - Gmail API, Microsoft Graph, IMAP, and unified layers like Unipile. This is distinct from transactional services (SendGrid, Mailgun) that send outbound email from your domain.

Build products that read user emails programmatically. From a single GET /api/v1/emails call to real-time webhooks, this guide covers every approach with working code in Node.js, Python, and cURL.

read_inbox.js
// Read emails with one unified API call const response = await fetch( 'https://api3.unipile.com:PORT/api/v1/emails', { headers: { 'X-API-KEY': process.env.UNIPILE_API_KEY, 'account_id': accountId } } ); const { emails } = await response.json(); // Same JSON shape for Gmail, Outlook & IMAP emails.forEach(email => { console.log(email.subject, email.from_attendee); });
200 OK - 47 emails returned (Gmail + Outlook + IMAP)
Works with: Gmail Outlook IMAP Gmail, Outlook & IMAP
Definition

What is a Read Email API?

A read email API is an HTTP interface that lets your application access, retrieve, and process emails from a user's existing mailbox - without storing passwords or building provider-specific integrations. It is the foundation of any product that needs inbox visibility: CRM sync, AI email copilots, support automation, or compliance archiving.

Quick definition

A read email API exposes endpoints to authenticate against a user's mailbox (via OAuth 2.0 or IMAP credentials), list inbox messages, fetch full email bodies with attachments, and subscribe to real-time delivery events. It operates on the user's existing Gmail, Outlook, or IMAP account - not a domain you control. This distinguishes it from transactional email APIs (SendGrid, Mailgun, Resend), which send outbound email on behalf of your application.

This guide covers
Sync / Read Email APIs

Connect to users' existing inboxes. Read, sync, and react to emails in real time. Auth via OAuth 2.0 or IMAP. The user grants access to their own mailbox.

Examples: Gmail API, Microsoft Graph, IMAP, Unipile
Not this guide
Transactional Email APIs

Send outbound emails from a domain you control. Used for receipts, notifications, password resets. No inbox access.

Examples: SendGrid, Mailgun, Resend, Postmark
Use Cases

Why Reading Emails Programmatically Matters

The ability to read user emails via API unlocks a category of products that were simply impossible with SMTP alone. Here are the four primary use cases driving adoption in 2026.

CRM and Sales Engagement Sync

Sales tools need to see every email thread between a rep and a prospect - automatically, without manual logging. A read email API pulls conversations directly from the rep's inbox and syncs them to your CRM in real time.

Auto-log email exchanges to contact records
Surface deal-relevant signals from inbox threads
Detect reply intent and update pipeline stage

AI Agents and Email Copilots

Large language models need context. By feeding your AI agent a real-time stream of inbox emails, you can build copilots that draft replies, summarise threads, extract action items, and prioritise conversations automatically.

Stream new emails to an LLM processing pipeline
Generate context-aware draft replies
Extract tasks, dates, and commitments from threads

Customer Support Automation

Support teams receive thousands of emails a day. A read email API lets your platform classify incoming requests, route them to the right queue, and trigger automated responses - all before a human ever opens a ticket.

Classify support emails by topic and urgency
Route to agent queues based on email content
Trigger auto-responses for common request patterns

Compliance, Archiving, and eDiscovery

Regulated industries must retain and index every email. A read email API provides the programmatic access needed to continuously archive inboxes, flag policy violations, and produce email records on demand for legal review.

Continuous inbox archiving for GDPR / FINRA compliance
Policy violation detection across employee mailboxes
eDiscovery export on demand for legal hold
Provider Deep Dive

Native APIs for Reading Emails: Gmail, Outlook, and IMAP

Each major email provider exposes its own read API with different endpoints, authentication models, and capabilities. Here is what each looks like in practice.

Gmail API

OAuth 2.0

The Gmail API is a REST API built on top of Google's infrastructure. It uses users.messages.list to paginate through a mailbox and users.messages.get to fetch a full message. It supports push notifications via Google Pub/Sub, making real-time inbox monitoring feasible without polling. Rate limit: 250 quota units per user per second.

gmail_read.sh
# List inbox messages (Gmail API) curl -X GET \ "https://gmail.googleapis.com/gmail/v1/users/me/messages?labelIds=INBOX&maxResults=20" \ -H "Authorization: Bearer ACCESS_TOKEN" # Fetch a single email with full body curl -X GET \ "https://gmail.googleapis.com/gmail/v1/users/me/messages/MESSAGE_ID?format=full" \ -H "Authorization: Bearer ACCESS_TOKEN"
Note: Gmail returns messages as base64-encoded MIME parts. You must decode each part and parse multipart boundaries yourself to extract the plain text body, HTML body, and attachments.

Microsoft Graph (Outlook and Microsoft 365)

OAuth 2.0

Microsoft Graph is the unified API for all Microsoft 365 services including Outlook personal accounts, Exchange Online, and Microsoft 365 business mailboxes. The /me/messages endpoint returns messages with full body content in a single request. Pagination uses $skip and $top OData parameters. See the full Microsoft Graph email integration guide for details.

graph_read.sh
# List inbox messages (Microsoft Graph) curl -X GET \ "https://graph.microsoft.com/v1.0/me/messages?\$top=20&\$filter=parentFolderId eq 'inbox'" \ -H "Authorization: Bearer ACCESS_TOKEN" \ -H "Content-Type: application/json" # Fetch a single message with body curl -X GET \ "https://graph.microsoft.com/v1.0/me/messages/MESSAGE_ID?\$select=subject,body,from,receivedDateTime" \ -H "Authorization: Bearer ACCESS_TOKEN"
Note: Microsoft Graph throttles at 10,000 requests per 10 minutes per application per tenant. Body content is returned as HTML or text depending on the $select and Accept headers.

IMAP

Universal Protocol

IMAP (Internet Message Access Protocol) is the universal email protocol supported by virtually every mail server. It is not a REST API but a stateful TCP connection over port 993 (TLS). You issue commands like FETCH, SEARCH, and IDLE over the connection. For a deeper dive, see our IMAP API integration guide.

imap_read.py
import imaplib, email # Connect and authenticate mail = imaplib.IMAP4_SSL('imap.example.com') mail.login('user@example.com', 'app_password') mail.select('INBOX') # Search for unseen messages status, message_ids = mail.search(None, 'UNSEEN') for msg_id in message_ids[0].split(): _, data = mail.fetch(msg_id, '(RFC822)') msg = email.message_from_bytes(data[0][1]) print(msg['subject'], msg['from'])
Note: IMAP requires maintaining long-lived TCP connections and managing connection pools yourself. Real-time delivery uses the IDLE command, which keeps a connection open and waits for server notifications. This does not scale easily beyond a few hundred concurrent accounts.
What about Yahoo and other providers?

Yahoo Mail, ProtonMail, Zoho, and other providers all support IMAP as a universal fallback, so they are covered by the IMAP approach above. Some (like Yahoo) also expose limited proprietary APIs, but none match the capabilities of the Gmail API or Microsoft Graph. For most multi-provider products, IMAP is the universal fallback for any mailbox not covered by Gmail or Outlook OAuth. A unified email API handles this negotiation automatically.

Engineering Reality

The Hidden Complexity of Reading Emails at Scale

Building a read email API integration against a single provider for a demo takes an afternoon. Building one that works reliably across all providers at production scale is a different challenge entirely. Here is what the engineering actually involves.

01

OAuth Flow Per Provider

Each provider has its own OAuth 2.0 implementation, consent screen requirements, scopes, and token lifecycle. Supporting Gmail and Outlook means maintaining two separate OAuth apps, two developer consoles, two token refresh strategies, and two sets of compliance requirements (Google CASA Tier 2, Microsoft Publisher Verification).

Gmail:Google Cloud Console app, CASA Tier 2 for sensitive scopes, 1-hour access tokens
Outlook:Azure AD app registration, Publisher Verification, configurable token TTL
IMAP:App passwords or OAuth (Gmail IMAP uses same Google OAuth flow)
02

Pagination Differences

Each provider paginates differently. Gmail uses opaque page tokens. Microsoft Graph uses OData $skip and nextLink cursors. IMAP uses numeric UID ranges. Implementing a consistent pagination abstraction across all three requires non-trivial adapter code.

Gmail:pageToken cursor, max 500 results per page
Graph:@odata.nextLink URL, $top/$skip parameters
IMAP:UID FETCH ranges, CONDSTORE for incremental sync
03

MIME Parsing

Emails arrive as raw MIME documents with nested multipart boundaries, base64 or quoted-printable encoding, multiple character sets, and inline attachments. Gmail returns base64url-encoded parts. IMAP returns raw RFC 822. Neither gives you a clean plain-text body without parsing the full MIME tree.

Risk:International characters, emoji, and RTL text introduce encoding edge cases that corrupt body content
Attachments:Must traverse the MIME tree to find Content-Disposition: attachment parts
04

Rate Limits and Backoff

Gmail enforces 250 quota units per user per second (listing costs 5 units, fetching 5 units). Microsoft Graph throttles at 10,000 requests per 10 minutes per app per tenant. Both return 429 errors that require exponential backoff with jitter. At 1,000 linked accounts, rate limit management becomes a full engineering problem.

Gmail:250 quota units/sec/user. Daily cap: 1 billion units
Graph:10,000 req / 10 min / app / tenant. Retry-After header
IMAP:Provider-specific, typically 10-20 concurrent connections per account
05

Real-Time: Webhooks vs Polling vs IDLE

Getting notified when a new email arrives requires completely different mechanisms per provider. Gmail uses Google Pub/Sub push subscriptions that must be renewed every 7 days. Microsoft Graph uses change notification subscriptions with a maximum lifetime of 4,230 minutes. IMAP uses the IDLE command, which keeps a persistent TCP connection open per account.

Gmail:Pub/Sub push, 7-day expiry, requires renew cycle
Graph:changeNotifications subscription, max ~3 days expiry
IMAP:IDLE command, 1 persistent TCP connection per account
06

Thread Inconsistencies Across Providers

Gmail groups messages into threads natively. Microsoft Graph has a conversationId field but threads behave differently from Gmail. IMAP has no native threading - you reconstruct threads by matching References and In-Reply-To headers manually. Building a cross-provider unified thread view requires significant normalization logic.

Gmail:Native threadId, messages.list?labelIds=INBOX returns thread groups
Graph:conversationId, but not equivalent to Gmail threads
IMAP:Must parse Message-ID / References headers manually
Architecture

Read Email API Architecture: 3 Approaches Compared

There is no single "correct" architecture for reading emails. The right approach depends on how many providers you need to support, your engineering bandwidth, and your scale requirements. Here is an honest comparison.

Approach Pros Cons When to use
Direct provider APIs
Gmail API, Microsoft Graph
Free tier, full feature access, no intermediary latency OAuth setup per provider, MIME parsing, separate rate limit management, no cross-provider normalization Single provider only
Self-hosted IMAP
imaplib, node-imap
Universal protocol, works with any mailbox, no OAuth app required Stateful TCP connections, no push notifications (polling or IDLE), connection pool management, slow at scale Legacy / on-prem only
Unified read email API
Unipile
One endpoint for all providers, normalized JSON response, managed OAuth, unified webhooks, built-in retry logic Additional API call cost per linked account, external dependency Multi-provider products
Direct provider APIs
Gmail API, Microsoft Graph
Pros Free tier, full feature access, no intermediary latency
Cons OAuth setup per provider, MIME parsing, separate rate limit management, no cross-provider normalization
When to use Single provider only
Self-hosted IMAP
imaplib, node-imap
Pros Universal protocol, works with any mailbox, no OAuth app required
Cons Stateful TCP connections, no push notifications (polling or IDLE), connection pool management, slow at scale
When to use Legacy / on-prem only
Unified read email API
Unipile
Pros One endpoint for all providers, normalized JSON response, managed OAuth, unified webhooks, built-in retry logic
Cons Additional API call cost per linked account, external dependency
When to use Multi-provider products
Best for single provider
Direct Provider API

If every user in your product uses Gmail, build directly against the Gmail API. You get full feature parity, no additional cost, and access to Gmail-specific features like labels, threads, and Pub/Sub push.

Best for legacy systems
Self-hosted IMAP

On-premises mail servers, enterprise Exchange deployments without Graph API access, or any scenario where OAuth is not available. Use IMAP as a fallback, not a primary strategy for new products.

Best for SaaS products
Unified Read Email API

When your users have Gmail, Outlook, and IMAP mailboxes and you need one consistent read email API across all of them, a unified layer like Unipile eliminates the N-provider integration problem entirely.

5-Minute Setup

Reading Emails with Unipile's Unified Read Email API

Unipile abstracts Gmail API, Microsoft Graph, and IMAP behind a single read email API. One OAuth flow, one endpoint, one normalized JSON shape - regardless of which provider your user's mailbox lives on. Here is how to get your first inbox read in under 5 minutes.

1
Authenticate a user with the hosted auth link

Generate a hosted authentication URL from your Unipile dashboard. Send this link to your user - they complete the OAuth consent flow for their provider (Gmail, Outlook, or IMAP credentials) on Unipile's hosted page. No OAuth app setup, no redirect URI configuration on your end. See the unified email API guide for the full auth flow.

auth_link.sh
# Generate a hosted auth link for your user curl -X POST \ "https://api3.unipile.com:PORT/api/v1/hosted/accounts/link" \ -H "X-API-KEY: YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"type":"EMAIL","name":"user@example.com","success_redirect_url":"https://yourapp.com/connected"}' # Response: { "url": "https://auth.unipile.com/..." } # Send this URL to your user - they complete OAuth on their provider
2
List inbox emails - GET /api/v1/emails

Once the user has linked their account, call the emails endpoint with their account_id. The response is identical whether the underlying mailbox is Gmail, Outlook, or IMAP.

list_emails.sh
# List inbox emails (works for Gmail, Outlook, and IMAP) curl -X GET \ "https://api3.unipile.com:PORT/api/v1/emails?account_id=ACCOUNT_ID&limit=50" \ -H "X-API-KEY: YOUR_API_KEY" # Filter by folder curl "...?account_id=ACCOUNT_ID&folder=INBOX&limit=50" -H "X-API-KEY: YOUR_API_KEY" # Filter unread only curl "...?account_id=ACCOUNT_ID&unread=true" -H "X-API-KEY: YOUR_API_KEY"
200 OK - normalized JSON, same shape for all providers
3
Get a single email with body and attachments

Fetch a full email by ID. Unipile returns a decoded, normalized object with plain text body, HTML body, and attachment metadata - no MIME parsing required on your end.

get_email.sh
# Fetch a single email with full body + attachments curl -X GET \ "https://api3.unipile.com:PORT/api/v1/emails/EMAIL_ID" \ -H "X-API-KEY: YOUR_API_KEY" # Response fields (always normalized): # { "id", "subject", "date", "from_attendee", "to_attendees", # "body", "body_plain", "attachments": [{ "id", "filename", "size" }] }
4
Receive new emails in real time via webhooks

Register a webhook endpoint in your Unipile dashboard. Unipile abstracts Gmail Pub/Sub, Microsoft Graph change notifications, and IMAP IDLE into a single email.received event. No subscription renewal, no IDLE connection pool to manage.

webhook_handler.js
// Unipile calls your endpoint when a new email arrives // Same event for Gmail, Outlook, and IMAP users app.post('/webhooks/email', (req, res) => { const { event, account_id, email_id } = req.body; if (event === 'email.received') { // Fetch the full email details processNewEmail(account_id, email_id); } res.sendStatus(200); });
One webhook event replaces Gmail Pub/Sub + Graph subscriptions + IMAP IDLE
Want the complete integration reference?

The full Email API Guide covers authentication, all endpoints, pagination, attachment downloads, security, and compliance in detail.

Read the Email API Guide
Code Examples

Reading Emails: Code Examples by Language

Production-ready snippets for reading emails with Unipile's unified read email API. All examples read from Gmail, Outlook, and IMAP accounts with the same code.

Node.js / TypeScript
Python
Go
readEmails.ts
import fetch from 'node-fetch'; const BASE = 'https://api3.unipile.com:PORT/api/v1'; const API_KEY = process.env.UNIPILE_API_KEY!; interface Email { id: string; subject: string; date: string; from_attendee: { display_name: string; identifier: string }; body: string; body_plain: string; attachments: { id: string; filename: string; size: number }[]; } // List inbox emails - works for Gmail, Outlook, and IMAP async function listEmails(accountId: string, limit = 50) { const res = await fetch( `${BASE}/emails?account_id=${accountId}&limit=${limit}&folder=INBOX`, { headers: { 'X-API-KEY': API_KEY } } ); const data = await res.json(); return data.items as Email[]; } // Fetch a single email with full body + attachments async function getEmail(emailId: string) { const res = await fetch(`${BASE}/emails/${emailId}`, { headers: { 'X-API-KEY': API_KEY } } ); return await res.json() as Email; } // Usage const emails = await listEmails('acc_01abc...'); emails.forEach(e => console.log(e.subject, e.from_attendee.identifier));
read_emails.py
import os import requests BASE = "https://api3.unipile.com:PORT/api/v1" HEADERS = {"X-API-KEY": os.environ["UNIPILE_API_KEY"]} def list_emails(account_id: str, limit: int = 50) -> list: """List inbox emails - works for Gmail, Outlook, and IMAP.""" resp = requests.get( f"{BASE}/emails", headers=HEADERS, params={ "account_id": account_id, "limit": limit, "folder": "INBOX", }, ) resp.raise_for_status() return resp.json()["items"] def get_email(email_id: str) -> dict: """Fetch a single email with body and attachments.""" resp = requests.get(f"{BASE}/emails/{email_id}", headers=HEADERS) resp.raise_for_status() return resp.json() # Usage emails = list_emails("acc_01abc...") for email in emails: print(email["subject"], email["from_attendee"]["identifier"]) # Fetch full body for first email full = get_email(emails[0]["id"]) print(full["body_plain"])
read_emails.go
package main import ( "encoding/json" "fmt" "net/http" "os" ) type Email struct { ID string `json:"id"` Subject string `json:"subject"` BodyPlain string `json:"body_plain"` } type ListResponse struct { Items []Email `json:"items"` } func listEmails(accountID string) ([]Email, error) { url := "https://api3.unipile.com:PORT/api/v1/emails?account_id=" + accountID req, _ := http.NewRequest("GET", url, nil) req.Header.Set("X-API-KEY", os.Getenv("UNIPILE_API_KEY")) resp, err := http.DefaultClient.Do(req) if err != nil { return nil, err } defer resp.Body.Close() var result ListResponse json.NewDecoder(resp.Body).Decode(&result) return result.Items, nil } func main() { emails, _ := listEmails("acc_01abc...") for _, e := range emails { fmt.Println(e.Subject) } }
Real-Time

Real-Time Email Reading: Webhooks vs Polling

Knowing when a new email arrives is as important as being able to read it. There are three mechanisms available, each with very different operational characteristics at scale.

Avoid at scale

Polling

Your application calls the list emails endpoint on a timer (every 30s, every 5 minutes). Simple to implement but burns quota, introduces latency, and does not scale beyond a handful of accounts.

Simple - no server-side setup
Burns API quota proportional to accounts x frequency
5-minute poll = 5-minute notification delay
Does not scale past ~100 active accounts
Provider-specific

Native Provider Webhooks

Gmail Pub/Sub and Microsoft Graph change notifications push events to your server immediately. Fast and quota-efficient - but each requires separate setup, separate renewal logic, and different event schemas.

Near-instant delivery (seconds)
Quota-efficient - only triggered on new emails
Gmail: Pub/Sub subscription expires every 7 days
Graph: subscription max ~3 days, must renew
IMAP IDLE: 1 TCP connection per account
Recommended

Unipile Unified Webhooks

Unipile abstracts all provider push mechanisms behind a single email.received event. One endpoint receives notifications for Gmail, Outlook, and IMAP accounts alike - with automatic subscription renewal handled internally.

One webhook URL for all providers
Automatic Pub/Sub and Graph renewal
IMAP IDLE managed internally per account
Normalized payload - same fields every time
How Unipile abstracts real-time email delivery

Under the hood, Unipile manages Gmail Pub/Sub subscriptions, Microsoft Graph change notification subscriptions, and IMAP IDLE connections - per linked account, automatically renewed. Your application registers one webhook URL and receives one normalized event regardless of the underlying provider.

Gmail Pub/Sub
+
Graph Subscriptions
+
IMAP IDLE
->
email.received event
Security & Compliance

Security and Compliance When Reading User Emails

Accessing user emails carries significant security and legal responsibilities. Here are the four areas you must address before shipping a read email API integration to production.

OAuth Scope Minimisation

Always request the minimum OAuth scope required. For reading emails, use read-only scopes - never request send or compose permissions if your application only needs inbox access. Gmail read-only scope is gmail.readonly. Microsoft Graph equivalent is Mail.Read. Requesting broad scopes triggers stricter Google and Microsoft review processes and reduces user trust at the consent screen.

Token Storage Best Practices

OAuth access tokens and refresh tokens are credentials. Store them encrypted at rest using AES-256 or equivalent, never in plaintext in your database. Rotate encryption keys on a schedule. Never log tokens in application logs. Implement token revocation when a user disconnects their account - call the provider's revocation endpoint, do not simply delete the database record.

GDPR and Data Residency

Email bodies often contain personal data covered by GDPR. You must document in your privacy policy exactly what email data you collect, retain, process, and for how long. Implement a data deletion flow that removes email content when a user requests erasure. If you store email content in your own infrastructure, consider data residency requirements for EU customers.

Google CASA and Microsoft Publisher Verification

Applications requesting sensitive Gmail scopes (including gmail.readonly) must complete Google's CASA Tier 2 security assessment before being allowed beyond the 100-user test cap. Microsoft requires Publisher Verification for apps requesting certain Graph scopes. Both processes take weeks - plan accordingly before your launch date. Using Unipile inherits these certifications from the platform layer.

Unipile compliance certifications

Unipile handles Gmail CASA Tier 2 certification, Microsoft Publisher Verification, SOC 2 Type II audit, and GDPR data processing agreements at the platform level. Products built on Unipile inherit these certifications rather than completing them independently.

SOC 2 Type II
Google CASA Tier 2
GDPR Compliant
OAuth 2.0 Read-only Scopes
Pricing

Read Email API Pricing: Free Tiers and Cost Models

The free tiers for native provider APIs are generous at low scale, but the hidden costs appear when you need to support multiple providers, manage token refresh at volume, or hit rate limit ceilings. Here is an honest breakdown.

Provider Free tier Cost model Rate limit Hidden costs
Gmail API Free with quotas Quota units per request. No per-account billing 250 units/sec/user, 1B units/day CASA Tier 2 review, MIME parsing, Pub/Sub renewal logic
Microsoft Graph Free with throttling Included with Microsoft 365 tenant. No per-call fee 10,000 req/10 min/app/tenant Publisher Verification process, subscription renewal, per-tenant OAuth apps
IMAP (self-hosted) Free protocol No API cost. Infrastructure cost for connection pools Provider-specific, ~10-20 connections/account Server infrastructure, IDLE connection management, no push support
Unipile 7-day free trial Per linked account per month. See free email API tier Managed internally, built-in retry logic API call cost per account - offset by eliminated OAuth/MIME engineering
Gmail API
Free with quotas
Cost model Quota units per request. No per-account billing
Rate limit 250 units/sec/user, 1B units/day
Hidden costs CASA Tier 2 review, MIME parsing, Pub/Sub renewal logic
Microsoft Graph
Free with throttling
Cost model Included with Microsoft 365 tenant. No per-call fee
Rate limit 10,000 req/10 min/app/tenant
Hidden costs Publisher Verification process, subscription renewal, per-tenant OAuth apps
IMAP (self-hosted)
Free protocol
Cost model No API cost. Infrastructure cost for connection pools
Rate limit Provider-specific, ~10-20 connections/account
Hidden costs Server infrastructure, IDLE connection management, no push support
Unipile
7-day free trial
Cost model Per linked account per month. See free email API tier
Rate limit Managed internally, built-in retry logic
Hidden costs API call cost per account - offset by eliminated OAuth/MIME engineering
Common Pitfalls

Common Pitfalls When Building a Read Email Integration

These are the mistakes that consistently cause production incidents for teams shipping their first read email API integration. Learn them before you hit them.

01
Quota exhaustion on Gmail at scale

Gmail's 250 quota units per second per user sounds generous until you have 500 accounts and need to do an initial inbox sync. Listing 500 messages costs 2,500 units; fetching each full message costs another 2,500. Initial syncs for large mailboxes can exhaust daily quotas in hours.

Fix: Implement exponential backoff on 429 responses, prioritise recent messages for initial sync, and use batch requests where available to reduce per-call overhead.
02
Silent token refresh failures

OAuth refresh tokens expire silently - Google revokes them after 6 months of inactivity, after a password change, or when a user revokes access from their Google Account settings. If your token refresh logic does not detect a 401 error and surface it to the user, your application will simply stop reading emails with no visible error.

Fix: Treat 401 responses as account disconnection events. Notify the user and prompt re-authentication. Store a last_sync_at timestamp and alert when it exceeds your expected sync interval.
03
Missing emails due to incorrect folder filters

Gmail labels and IMAP folders are not equivalent concepts. Gmail's INBOX label does not include messages that have been archived (removed from INBOX but not deleted). Microsoft Graph's inbox folder excludes focused inbox vs other pane splits unless you query both. Teams frequently discover they are missing 20-40% of messages due to mismatched folder assumptions.

Fix: Test your folder queries with real accounts including archived, filtered, and categorised messages. For comprehensive sync, consider querying ALL messages (not just INBOX) and filtering by date on your side.
04
Encoding bugs on international emails

Email bodies arrive in a wide range of character encodings: UTF-8, ISO-8859-1, Windows-1252, Shift-JIS. Gmail returns base64url-encoded parts. IMAP returns quoted-printable encoded parts. Decoding one encoding as another produces corrupted body text that is invisible in your local test environment (which likely only sends ASCII emails).

Fix: Always decode MIME parts according to their Content-Transfer-Encoding and re-encode to UTF-8. Test with Japanese, Arabic, and emoji-heavy email content specifically.
05
Threading inconsistencies across providers

Building a unified thread view across Gmail, Outlook, and IMAP accounts requires normalising three completely different threading models. Gmail has native thread IDs. Outlook has conversation IDs that behave differently. IMAP has no native threading at all - you reconstruct threads from Message-ID, References, and In-Reply-To headers, which are not always present or correct.

Fix: A unified read email API like Unipile normalises threading into a consistent model across all providers, eliminating the need to implement provider-specific thread reconstruction logic.
FAQ

Read Email API - Frequently Asked Questions

The most common questions from developers building their first read email API integration.

01
What is a read email API?
A read email API is an HTTP interface that lets your application authenticate against a user's existing mailbox (via OAuth 2.0 or IMAP credentials) and retrieve email messages programmatically. It is distinct from transactional email APIs like SendGrid or Mailgun, which send outbound email from a domain you control. Read email APIs operate on the user's own Gmail, Outlook, or IMAP account. See the full comparison of email API providers for context on the broader ecosystem.
02
Can I read someone's email with an API?
You can only read emails from accounts where the mailbox owner has explicitly granted your application access via OAuth 2.0 consent. The user must authorize your application on Google's or Microsoft's consent screen. You cannot access emails without the account owner's consent - attempting to do so violates provider terms of service and applicable law in most jurisdictions.
03
How do I read emails using the Gmail API?
To read emails with the Gmail API: create a Google Cloud project, enable the Gmail API, configure an OAuth 2.0 client, request the gmail.readonly scope, obtain an access token via OAuth consent, then call GET /gmail/v1/users/me/messages to list messages and GET /users/me/messages/{id}?format=full to fetch individual emails. Messages are returned as base64url-encoded MIME parts that you must decode.
04
What is the difference between IMAP and the Gmail API?
The Gmail API is a modern REST API with OAuth 2.0, push notifications via Google Pub/Sub, and JSON responses. IMAP is a universal TCP protocol supported by every email provider, using stateful connections and text commands. The Gmail API is more capable for Gmail-only use cases (real-time push, thread access, label management). IMAP provides universal coverage across all providers but requires polling or IDLE connections and has no native REST interface. Read our IMAP API integration guide for a deeper comparison.
05
Is there a free API to read emails?
Yes. The Gmail API is free within Google's quota limits (250 units/sec/user, 1 billion units/day). Microsoft Graph for Outlook is free with throttling limits. IMAP is a free open protocol. For multi-provider support, Unipile offers a 7-day free trial covering Gmail, Outlook, and IMAP linked accounts. See our free email API guide for a full comparison of free tiers and their real-world limits.
06
How do I read emails from multiple providers with one API?
Use a unified read email API like Unipile. Unipile exposes a single endpoint (GET /api/v1/emails) that returns normalized JSON for Gmail, Outlook, and IMAP accounts alike. You authenticate users once via a hosted OAuth link, and Unipile handles the provider-specific OAuth flows, MIME parsing, and real-time webhook abstraction behind a single consistent interface. See our Email API Guide for the complete reference.
07
Can I read email attachments via API?
Yes. The Gmail API returns attachment metadata in the message payload and provides a separate endpoint to download attachment data by ID. Microsoft Graph returns attachments via /messages/{id}/attachments. IMAP requires parsing the MIME tree to identify attachment parts. With Unipile, attachment metadata (filename, size, MIME type) is included in the email response and attachment content is available via a dedicated endpoint - no MIME parsing required.
08
How do I get notified when a new email arrives?
Each provider has a different mechanism: Gmail uses Google Pub/Sub push subscriptions (expire every 7 days, require renewal). Microsoft Graph uses change notification subscriptions (expire after ~3 days). IMAP uses the IDLE command over a persistent TCP connection. Alternatively, Unipile abstracts all three into a single email.received webhook event that fires for Gmail, Outlook, and IMAP accounts with automatic subscription management handled internally.
09
What are the rate limits for reading emails on Gmail and Outlook?
Gmail API: 250 quota units per user per second. Listing messages costs 5 units, fetching a full message costs 5 units. Daily cap is 1 billion quota units. Microsoft Graph: 10,000 requests per 10 minutes per application per tenant. Both return HTTP 429 when throttled, with a Retry-After header. Implement exponential backoff with jitter for production reliability. IMAP limits are provider-specific, typically 10-20 concurrent connections per account.
10
Is reading user emails via API GDPR compliant?
Reading user emails via API can be GDPR compliant when implemented correctly. Requirements include: explicit user consent via OAuth (the consent screen fulfils the lawful basis requirement), a privacy policy documenting what email data you collect and retain, a data deletion mechanism for erasure requests, and a data processing agreement with any third-party API layer you use. Unipile is SOC 2 Type II certified and GDPR compliant, simplifying the compliance documentation for products built on the platform.

Still have questions? Talk to a developer who has shipped read email API integrations across Gmail, Outlook, and IMAP at scale.

Talk to an expert
en_USEN