Build an AI Email Assistant with Claude: Full Guide
If you want to build an AI email assistant with Claude, the core architecture is simpler than most people expect: pull incoming messages from an email provider, send the relevant context to Claude with a clear system prompt, and use the model's output to draft, classify, or summarize before a human (or an automated rule) decides what happens next. The hard parts aren't the AI calls — they're email plumbing, context windows, and making sure the assistant never sends something it shouldn't without review.
This guide walks through a working design: how to structure prompts for email tasks, how to use tool calling for structured actions like "draft reply" or "flag as urgent," how to handle threads and attachments, and how to keep the whole thing production-ready with streaming and usage tracking.
What an AI email assistant actually needs to do
Most email assistants built on Claude handle a combination of these tasks:
- Triage — classify incoming mail (urgent, spam-like, newsletter, needs-reply)
- Summarization — condense long threads into 2-3 sentences
- Draft generation — write a reply in the user's tone, referencing thread context
- Extraction — pull dates, action items, or attachments into structured data
- Search and recall — answer "what did I agree to in that thread with Acme?"
Each of these is a separate prompt pattern, not one giant "email agent" prompt. Trying to do triage, summarization, and drafting in a single call tends to produce worse results than three focused calls with tighter instructions.
Step 1: Get email data into a usable format
Whether you're using Gmail API, Microsoft Graph, or IMAP, normalize each message into a simple JSON object before it touches Claude:
{
"thread_id": "t_8821",
"from": "client@example.com",
"subject": "Contract renewal",
"body_text": "Hi, following up on the renewal terms we discussed...",
"prior_messages": ["...", "..."]
}
Strip HTML down to plain text, truncate quoted signature blocks, and cap thread history to the last few messages (older context can be summarized separately if the thread is long). This keeps token usage predictable and avoids feeding the model boilerplate that dilutes the actual content.
Step 2: Write a system prompt per task
A triage prompt and a drafting prompt should not share the same system message. Keep them separate and specific:
You are an email triage assistant. Given an email, classify it into exactly
one category: urgent, needs_reply, fyi, newsletter, spam_like.
Respond with only the category name, nothing else.
You draft email replies in a professional but friendly tone, matching the
sender's level of formality. Never invent facts not present in the thread.
If information is missing, draft a reply that asks a clarifying question
instead of guessing.
The "never invent facts" instruction matters more here than in almost any other use case — a hallucinated commitment in a drafted email is a real business risk, not a cosmetic bug.
Step 3: Use tool calling for structured actions
Rather than parsing free text to decide what the assistant should do next, define tools and let Claude call them directly. This is cleaner for triage-and-act workflows:
{
"name": "classify_and_route",
"description": "Classify an email and choose the next action",
"input_schema": {
"type": "object",
"properties": {
"category": { "type": "string", "enum": ["urgent", "needs_reply", "fyi", "spam_like"] },
"suggested_action": { "type": "string", "enum": ["draft_reply", "archive", "notify_user"] },
"summary": { "type": "string" }
},
"required": ["category", "suggested_action", "summary"]
}
}
This gives you a predictable JSON payload back instead of free-form text you have to regex out. If you're new to defining tools for Claude, /docs/tools covers the schema format and required fields in detail.
Step 4: Stream draft generation for a responsive UI
If your assistant shows a live "writing reply..." experience, stream the completion rather than waiting for the full response. This matters especially for longer drafts where users expect to see progress instead of a spinner. Streaming setup is covered in /docs/streaming, and the pattern is the same regardless of provider: read server-sent events and append tokens to the UI as they arrive.
Step 5: Keep a human in the loop for sending
The single most important product decision in an email assistant is where the human review step lives. Fully autonomous sending is rarely a good idea for anything beyond internal, low-stakes notifications. A reasonable default:
- Claude drafts a reply
- Draft is shown to the user with an edit box
- User approves or edits, then sends
- Only fully rule-based, low-risk categories (e.g., "out of office auto-reply") skip review
This keeps the assistant genuinely useful without creating a support disaster the first time it misreads sarcasm or context.
Handling scale and API access
Once you're processing more than a handful of mailboxes, you'll want centralized API key management, usage tracking per user or team, and a stable HTTPS endpoint rather than juggling raw provider credentials across services. This is where SubToAPI fits into the stack: it turns your existing Claude access into application API keys (sub_live_...) with streaming, tool use, and usage metadata built in, so you're not building auth and quota tracking from scratch. Sign up at /signup, check /pricing for plan details, and follow /docs/quickstart to get a working call in a few minutes. The core request/response shape for drafting and classification calls is documented at /docs/messages.
A minimal draft-generation call looks like this:
curl https://api.subtoapi.app/v1/messages \
-H "Authorization: Bearer $SUBTOAPI_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-sonnet",
"max_tokens": 400,
"system": "You draft professional email replies. Never invent facts.",
"messages": [
{ "role": "user", "content": "Draft a reply to: Can we push the deadline to Friday?" }
]
}'
Common mistakes to avoid
- Sending the entire mailbox as context. Only pass the active thread and, if needed, a summarized history — not every past email with that contact.
- One prompt for everything. Separate triage, summarization, and drafting into distinct calls with distinct system prompts.
- No review step before sending. Even a 95%-accurate draft assistant will produce a bad email eventually; make review the default, not the exception.
- Ignoring attachments and formatting. Strip HTML and signature blocks before sending body text to the model to avoid wasted tokens and noisy output.
questions
Can Claude read and reply to emails directly, or do I need a separate integration? Claude itself only processes text you send it — it has no native email access. You need an integration layer (Gmail API, Microsoft Graph, or IMAP) that pulls messages, formats them, and sends the generated draft back through the provider's send endpoint.
How do I stop the assistant from sending inaccurate information? Instruct it explicitly to avoid inventing facts and to ask clarifying questions when information is missing, and keep a human review step before any reply is actually sent. Structured tool calls also reduce ambiguity compared to free-text parsing.
What's the cheapest way to get started without managing raw API infrastructure? Start with a small triage-and-draft prototype using a single mailbox, then route calls through a managed layer like SubToAPI for key management, streaming, and usage tracking as you add more users — see /docs/quickstart for the initial setup.