Guide
Email APIs for AI Agents Compared
Your AI agent needs to read, send, and search email. There are six common ways to do it: Gmail API, Microsoft Graph API, SendGrid/Mailgun/Postmark, direct IMAP, Nylas API, and Nylas CLI. Each has different auth complexity, provider coverage, and agent-friendliness. This guide compares all six across 14 criteria, with code examples showing how agents actually call each one. Covers Gmail, Outlook, Exchange, Yahoo, iCloud, and IMAP providers.
By Nick Barraclough
Disclosure: Nylas CLI is built by Nylas, the publisher of this guide. We present factual comparisons, but readers should be aware of this relationship.
The problem: 6 options, wildly different trade-offs
You're building an AI agent that needs email access. Maybe it triages support tickets. Maybe it extracts OTP codes. Maybe it schedules meetings by reading calendar invites. Whatever the use case, you need an API to give it inbox access.
The six options break into three categories: provider-specific APIs (Gmail API, Microsoft Graph), send-only services (SendGrid, Mailgun, Postmark), and multi-provider solutions (IMAP, Nylas). Each comes with different setup time, provider coverage, and agent compatibility.
Gmail API
The Gmail API gives full read/write access to Gmail and Google Workspace accounts. It's the official way to programmatically access Gmail.
The catch: setup takes 30+ minutes. You need a GCP project, an OAuth consent screen (1-6 weeks for external app review), scope selection, credential creation, and custom token refresh logic. Messages come back as base64url-encoded MIME, which you'll need to parse. Watch-based push notifications expire every 48 hours and must be renewed.
According to Google's Gmail API docs, the messages.send endpoint costs 100 quota units per call, and each user gets 250 units per second. An agent sending 3 emails per second will hit rate limits.
# Gmail API: what your agent code looks like
# 1. Authenticate (custom OAuth2 flow)
# 2. Build base64url MIME message
# 3. Handle token refresh on 401
# 4. Parse base64url MIME response
# 5. Implement exponential backoff for 429s
import base64
from email.mime.text import MIMEText
from googleapiclient.discovery import build
message = MIMEText("Hello from my agent")
message["to"] = "user@example.com"
message["subject"] = "Agent update"
raw = base64.urlsafe_b64encode(message.as_bytes()).decode()
service = build("gmail", "v1", credentials=creds)
service.users().messages().send(
userId="me", body={"raw": raw}
).execute()Best for: Google Workspace-only deployments where you already have GCP infrastructure. Agents that need Gmail-specific features like labels and Pub/Sub push.
Microsoft Graph API
Microsoft Graph provides email, calendar, and contacts access for Outlook and Microsoft 365 accounts. It's the successor to Exchange Web Services (EWS), which Microsoft is deprecating in October 2026.
The catch: requires an Azure AD app registration, MSAL token handling, and Microsoft-specific message formats. The permission model has two modes (delegated and application), each with different scopes. Throttling returns 429 with a Retry-After header your agent must respect.
# Microsoft Graph: what your agent code looks like
import msal
import requests
app = msal.ConfidentialClientApplication(
client_id, authority=authority,
client_credential=client_secret
)
# Acquire token (handle refresh, cache, retry)
result = app.acquire_token_for_client(
scopes=["https://graph.microsoft.com/.default"]
)
# Send email (Microsoft-specific JSON format)
requests.post(
"https://graph.microsoft.com/v1.0/me/sendMail",
headers={"Authorization": f"Bearer {result['access_token']}"},
json={
"message": {
"subject": "Agent update",
"body": {"contentType": "Text", "content": "Hello"},
"toRecipients": [
{"emailAddress": {"address": "user@example.com"}}
]
}
}
)Best for: Microsoft 365-only organizations. Agents that need Exchange Online features like shared mailboxes and room calendars.
SendGrid / Mailgun / Postmark
These are transactional email services. They send email reliably at scale, with deliverability tracking, bounce handling, and template engines.
The catch: they're send-only. SendGrid, Mailgun, and Postmark can't read your inbox, search messages, or access calendar data. An agent that needs to both read and send email can't use these alone. Mailgun offers an Inbound Routes feature for receiving, but it requires DNS MX record changes and webhook handling.
SendGrid's free tier allows 100 emails per day. Mailgun offers 1,000 emails in the first month, then requires a paid plan. Postmark charges $1.25 per 1,000 emails.
# SendGrid: send-only example
import sendgrid
sg = sendgrid.SendGridAPIClient(api_key="SG.xxx")
sg.send({
"personalizations": [{"to": [{"email": "user@example.com"}]}],
"from": {"email": "agent@yourdomain.com"},
"subject": "Agent notification",
"content": [{"type": "text/plain", "value": "Task complete."}]
})
# But where's the "read inbox" call?
# It doesn't exist. SendGrid can't read email.Best for: Agents that only send outbound notifications, alerts, or reports. Not suitable for agents that need to read and respond to email.
Direct IMAP
IMAP (Internet Message Access Protocol) is the underlying protocol that most email providers support. It gives you raw access to mailboxes, folders, and messages.
The catch: IMAP wasn't designed for agents. There's no push notification standard that works reliably across providers (IDLE is limited to one folder). Messages come as raw MIME, which requires parsing multi-part content, decoding base64 attachments, and handling character encoding edge cases. Each provider has its own credential requirements: Gmail needs OAuth2 tokens, Yahoo uses app passwords, iCloud requires app-specific passwords.
# Direct IMAP: raw protocol access
import imaplib
import email
# Connect (credentials differ by provider)
imap = imaplib.IMAP4_SSL("imap.gmail.com")
imap.login("user@gmail.com", "oauth2_token") # or app password
# Select inbox
imap.select("INBOX")
# Search (IMAP search syntax, not full-text)
_, message_ids = imap.search(None, "FROM", '"boss@company.com"')
# Fetch and parse MIME (the hard part)
for mid in message_ids[0].split():
_, data = imap.fetch(mid, "(RFC822)")
msg = email.message_from_bytes(data[0][1])
subject = msg["subject"]
# Now decode the body (might be multipart, might be base64,
# might be quoted-printable, might be nested...)
# No JSON output. No calendar. No contacts.
# Can't send without SMTP (separate connection).Best for: Agents that need raw protocol access, work with niche providers, or operate in environments where third-party APIs aren't allowed.
Nylas API and Nylas CLI
Nylas provides a unified API that normalizes email, calendar, and contacts across 6 providers (Gmail, Outlook, Exchange, Yahoo, iCloud, IMAP). The Nylas CLI wraps this API in a command-line tool with JSON output, a built-in MCP server for AI agents, and non-interactive mode for scripting.
Setup takes about 2 minutes: install the CLI, run nylas auth login, and start running commands. OAuth is handled automatically. Token refresh is internal. Rate limit retries are built in.
# Nylas CLI: complete setup + first email
brew install nylas/nylas-cli/nylas
nylas auth login # browser-based OAuth, any provider
nylas email list --json --limit 5
# Send email
nylas email send --to user@example.com \
--subject "Agent update" --body "Task complete." --yes
# Search inbox
nylas email search "invoice Q4" --json
# Calendar access (same tool, same auth)
nylas calendar events list --json
# AI agent integration via MCP
nylas mcp install --assistant claude-codeThe Nylas CLI is free, open-source, and MIT licensed. The MCP server exposes 16 tools that Claude Code, Cursor, VS Code, and Windsurf can call natively. For production applications, the Nylas API offers the same multi-provider coverage with SDKs in Python, Node.js, Ruby, and Java.
Best for: Agents that need multi-provider email access, agents that also need calendar and contacts, and any project where setup speed matters.
The comparison table
All six options, 14 criteria. Evaluate based on what your agent actually needs.
| Capability | Gmail API | Graph API | SendGrid | IMAP | Nylas CLI |
|---|---|---|---|---|---|
| Read inbox | Yes | Yes | No | Yes | Yes |
| Send email | Yes | Yes | Yes | Via SMTP | Yes |
| Search messages | Yes | Yes | No | Limited | Yes |
| Calendar access | Separate API | Yes | No | No | Yes |
| Contacts access | Separate API | Yes | No | No | Yes |
| Provider count | 1 (Gmail) | 1 (Microsoft) | N/A | Any | 6 |
| Auth complexity | High (GCP + OAuth) | High (Azure AD + MSAL) | Low (API key) | Medium (per-provider) | Low (one command) |
| JSON output | Yes (after MIME decode) | Yes | N/A | No (raw MIME) | Yes (--json) |
| MCP server | No | No | No | No | Yes (16 tools) |
| Webhook support | Pub/Sub (48h expiry) | Subscriptions | Yes (send events) | No (must poll) | Yes |
| Rate limit handling | Manual backoff | Manual backoff | Built-in | Provider-dependent | Built-in |
| Open source | Client libs only | Client libs only | Client libs only | Protocol | Yes (MIT) |
| CLI available | No | No | No | Via mutt/mailx | Yes |
| Agent-friendly | API client | API client | API client | Library | Subprocess + MCP |
Which to use when
Pick based on your constraints, not brand preference:
- All your users are on Gmail / Google Workspace? Gmail API. You'll write more code, but you get Google-specific features like labels, Pub/Sub push, and Workspace admin APIs.
- All your users are on Microsoft 365? Graph API. Same trade-off: more code, but you get shared mailboxes, room calendars, and Teams integration.
- Your agent only sends notifications? SendGrid or Postmark. Fast setup, high deliverability, good analytics. Don't try to make them read inboxes.
- You need raw protocol access or work with niche providers? Direct IMAP. Most flexible, most work.
- You need multi-provider read+send+search+calendar? Nylas CLI or Nylas API. One integration, 6 providers, JSON output, MCP server for agents.
Agent integration patterns
AI agents consume email APIs in three ways: as an API client in code, as a subprocess call, or through an MCP server. Here's how each option looks in practice.
Pattern 1: API client (Gmail API, Graph API, SendGrid)
Your agent calls the API through a language SDK. This means writing tool definitions, handling auth, and parsing responses.
# Agent tool definition for Gmail API
def gmail_list_messages(query: str, max_results: int = 10) -> list:
"""List Gmail messages matching a search query."""
service = build("gmail", "v1", credentials=get_credentials())
results = service.users().messages().list(
userId="me", q=query, maxResults=max_results
).execute()
messages = []
for msg_ref in results.get("messages", []):
msg = service.users().messages().get(
userId="me", id=msg_ref["id"], format="full"
).execute()
# Decode base64url MIME body
# Handle multipart content
# Extract headers
messages.append(parse_gmail_message(msg))
return messagesPattern 2: Subprocess (Nylas CLI, IMAP tools)
Your agent shells out to a CLI command and parses the JSON output. No SDK, no auth code, no token management.
# Agent tool definition for Nylas CLI
import subprocess
import json
def email_list(query: str = "", limit: int = 10) -> list:
"""List recent emails, optionally filtered by search query."""
cmd = ["nylas", "email", "list", "--json", "--limit", str(limit)]
if query:
cmd = ["nylas", "email", "search", query, "--json", "--limit", str(limit)]
result = subprocess.run(cmd, capture_output=True, text=True)
return json.loads(result.stdout)
def email_send(to: str, subject: str, body: str) -> dict:
"""Send an email."""
result = subprocess.run([
"nylas", "email", "send",
"--to", to, "--subject", subject, "--body", body,
"--json", "--yes"
], capture_output=True, text=True)
return json.loads(result.stdout)Pattern 3: MCP server (Nylas CLI only)
The agent connects to an MCP server that provides pre-defined tools. No custom tool code needed. Claude Code, Cursor, and VS Code connect natively.
# Install MCP for your AI assistant -- one command
nylas mcp install --assistant claude-code
# That's it. Your agent now has 16 tools:
# - list_messages, send_message, search_messages
# - create_draft, update_draft, send_draft
# - list_events, create_event, update_event
# - list_contacts, search_contacts
# - and more
# Test it by asking your agent:
# "What emails did I get from Sarah today?"
# "Send a reply saying I'll review the contract by Friday"
# "Create a meeting for tomorrow at 2pm with the team"The MCP pattern eliminates tool definition boilerplate entirely. For agents running in Claude Code, Cursor, or VS Code, it's the fastest path from zero to working email access.
JSON output comparison
Agents need structured data. Here's what each option returns for a simple "list recent emails" call:
# Gmail API response (simplified)
{
"messages": [
{
"id": "18e4b2c3d4e5f6a7",
"payload": {
"headers": [
{"name": "From", "value": "Sarah <sarah@company.com>"},
{"name": "Subject", "value": "Q4 Report"}
],
"body": {"data": "SGVsbG8gZnJvbSBTYXJhaA=="}
}
}
]
}
# Nylas CLI response (nylas email list --json --limit 1)
[
{
"id": "a1b2c3d4e5f6g7h8",
"subject": "Q4 Report",
"from": [{"name": "Sarah", "email": "sarah@company.com"}],
"date": "2026-03-28T10:30:00-04:00",
"unread": true,
"snippet": "Hello from Sarah..."
}
]The Gmail API response requires base64url decoding and header extraction. The Nylas CLI response is ready for jq, Python json.loads(), or direct LLM consumption.
Setup time comparison
| Option | Estimated setup time | What's involved |
|---|---|---|
| Gmail API | 1-4 hours (days if external review) | GCP project, OAuth consent, credentials, token storage |
| Graph API | 1-3 hours | Azure AD app, MSAL config, permission grants |
| SendGrid | 15 minutes | Account creation, API key, domain verification |
| IMAP | 30-60 minutes | Per-provider credentials, MIME parser, connection handling |
| Nylas CLI | 2 minutes | brew install + nylas auth login |
Frequently asked questions
Can I use multiple options together?
Yes. Many teams use SendGrid for outbound transactional email and Nylas CLI for agent inbox access. The tools don't conflict. Use whatever fits each use case.
What about the cost of each option?
Gmail API and Graph API are free (you're paying for Workspace or M365 already). SendGrid's free tier covers 100 emails/day. Mailgun is free for the first month, then starts at $0.80/1,000 emails. IMAP is free (it's a protocol). Nylas CLI is free and open-source (MIT license).
Does Nylas CLI store my email data?
The CLI authenticates via OAuth and accesses email through the Nylas API. Messages aren't stored locally beyond the JSON output of individual commands. Token credentials are stored in your system keychain.
Can I switch from Gmail API to Nylas CLI without changing my agent's code?
If your agent calls the Gmail API directly, you'll need to swap the tool definitions. If your agent uses subprocess calls, replace the Gmail SDK code with nylas email list --json and nylas email send commands. The MCP pattern requires the least agent-side code changes since it's tool-definition-free.
Next steps
- Give AI agents email access via MCP -- set up the MCP server for Claude, Cursor, or VS Code
- Give your AI coding agent an email address -- connect Claude Code, Cursor, Codex CLI, and OpenClaw
- Build an AI email triage agent -- put your chosen API to work classifying and responding to email
- Nylas CLI vs Recall.ai -- email/calendar vs meeting recordings for agents
- Build an LLM agent with email tools -- subprocess patterns for custom agents
- Why Gmail API breaks AI agents -- deep dive into Gmail API friction points
- Full command reference -- every flag, subcommand, and example