Email triage is one of those tasks that sounds simple until you’re actually building it. You need to read the message, understand the intent, classify it correctly, and route it somewhere useful — all without triggering on every newsletter or calendar invite. An n8n Claude workflow handles this elegantly because you get Claude’s language understanding wired directly into n8n’s routing logic, without standing up any custom infrastructure. This guide walks through the full implementation: connecting Gmail, calling Claude via the HTTP Request node, parsing the response, and branching into different routing paths based on classification output.
This isn’t a toy example. The setup below is close to what I’d ship for a small support team or a solo founder who needs to stop triaging email manually every morning.
What You’re Building
The workflow does four things in sequence:
- Polls a Gmail inbox for unread messages every 5 minutes
- Sends each email’s subject and body to Claude for classification
- Parses Claude’s structured JSON response to extract category and urgency
- Routes to different downstream nodes based on that classification
Downstream actions in this example are: creating a Notion ticket for support requests, forwarding sales inquiries to a Slack channel, and auto-labeling everything else in Gmail. You can swap those for whatever makes sense in your context — the classification and routing logic is the reusable part.
Prerequisites
- n8n instance (self-hosted or n8n Cloud — both work; I’m using self-hosted 1.x)
- Anthropic API key (get one at console.anthropic.com)
- Gmail OAuth credentials configured in n8n
- Optionally: Slack and Notion API tokens for the routing destinations
Step 1: The Gmail Trigger Node
Use the Gmail Trigger node set to “Message Received” with a poll interval of 5 minutes. Filter for unread messages in your inbox or a specific label. If you’re testing against a real inbox, apply a label filter immediately — otherwise you’ll classify 400 old newsletters on first run and burn through tokens unnecessarily.
The node outputs each email as an item with fields including subject, text, from, and id. The text field is the plain-text body; if you need HTML parsing, add a Function node to strip tags first. For most triage purposes, plain text is sufficient and cheaper to send to the model.
One thing the n8n docs don’t emphasize clearly: Gmail’s push notification mode via Pub/Sub is much faster than polling, but it requires a publicly accessible webhook URL and GCP setup. For most use cases, polling every 5 minutes is fine and dramatically simpler to maintain.
Step 2: Calling Claude via HTTP Request
n8n doesn’t have a native Claude node yet (as of mid-2025), so you use the HTTP Request node pointing at the Anthropic Messages API. This is actually fine — the HTTP Request node in n8n is flexible enough that you’re not missing much.
Configure the HTTP Request node as follows:
- Method: POST
- URL:
https://api.anthropic.com/v1/messages - Authentication: Header Auth → add
x-api-keywith your Anthropic key, andanthropic-version: 2023-06-01 - Body Content Type: JSON
Here’s the body you want to send. The key is using a structured output prompt so Claude returns something your next node can parse reliably:
{
"model": "claude-haiku-4-5",
"max_tokens": 256,
"system": "You are an email classifier. Respond only with valid JSON — no explanation, no markdown. Use this exact schema: {\"category\": string, \"urgency\": string, \"summary\": string}. Category must be one of: support, sales, billing, spam, internal, other. Urgency must be one of: high, medium, low.",
"messages": [
{
"role": "user",
"content": "Classify this email.\n\nFrom: {{ $json.from }}\nSubject: {{ $json.subject }}\nBody:\n{{ $json.text.slice(0, 1500) }}"
}
]
}
Note the .slice(0, 1500) on the body. This caps the input so a single long email doesn’t balloon your token count. For most triage purposes, the first 1500 characters of the body contains enough signal. If you’re dealing with threaded emails, you may want to extract just the most recent reply.
Choosing the Right Claude Model
For simple classification like this, Claude Haiku is the right call. At roughly $0.00025 per 1K input tokens and $0.00125 per 1K output tokens, a typical 500-token request with a 100-token response costs about $0.0002. Running this on 500 emails per day costs roughly $0.10/day. Claude Sonnet is about 5x more expensive and meaningfully smarter, but classification with a tight prompt doesn’t need that capability ceiling. Save Sonnet for when you need reasoning, drafting, or nuanced judgment.
I’d avoid using GPT-4o here not because it’s worse but because you’re already building in n8n and the Anthropic API is cleaner for structured outputs with explicit system prompts. Claude also tends to respect JSON-only output instructions more reliably in my testing — GPT models occasionally wrap JSON in markdown code fences even when you explicitly say not to.
Step 3: Parsing Claude’s Response
The HTTP Request node returns the raw API response. Claude’s reply is nested at content[0].text. You need a Code node (JavaScript) to extract and parse it:
// Input: raw Anthropic API response
const rawText = $input.item.json.content[0].text;
let parsed;
try {
parsed = JSON.parse(rawText);
} catch (e) {
// Fallback if Claude returns malformed JSON (rare but happens)
parsed = {
category: "other",
urgency: "low",
summary: "Failed to parse classification"
};
}
// Merge classification back with original email data
return {
json: {
...($input.item.json._original || {}), // pass through email fields if you set them upstream
category: parsed.category,
urgency: parsed.urgency,
summary: parsed.summary
}
};
The try/catch matters here. In production, Claude very occasionally returns a response that starts with a space or has a trailing comment — both break JSON.parse(). The fallback routes to “other/low” which is safe: it won’t get auto-deleted, it’ll just land in a catch-all pile for manual review.
One thing that will trip you up: if you need the original email fields (subject, from, id) available after this node, you need to either pass them through explicitly or use n8n’s “Merge” node to combine the classification output with the original item. The Code node doesn’t automatically inherit upstream fields.
Step 4: Routing with the Switch Node
Now the interesting part. Add a Switch node after the Code node. Route on {{ $json.category }}:
- support → Notion “Create Page” node to log a support ticket
- sales → Slack “Send Message” node to your #sales channel
- billing → Gmail “Add Label” node (label: “billing-review”) + optional Slack ping
- spam → Gmail “Add Label” node (label: “auto-spam”) + Gmail “Mark as Read”
- Default (other/internal) → Gmail “Add Label” node (label: “ai-processed”)
You can add a second level of routing inside the “support” branch based on urgency — if urgency === "high", also send a Slack ping to whoever is on-call. This is where the structured output from Claude pays off: you’re just branching on clean string values, not parsing freeform text.
Adding Context to Slack Notifications
When posting to Slack, use Claude’s summary field to make the notification useful. A Slack message like this is much more actionable than just “new email received”:
📧 New {{ $json.urgency }} urgency sales inquiry
From: {{ $json.from }}
Subject: {{ $json.subject }}
Summary: {{ $json.summary }}
What Breaks in Production
A few things you’ll hit once this is running on real volume:
Rate limits. The Anthropic API has per-minute token limits that vary by tier. If you have a burst of 50 emails arrive simultaneously (think: a newsletter to a catch-all), you’ll hit rate limits. Add a Wait node between the Gmail trigger and the HTTP Request node with a short delay, or handle 429 responses with the HTTP Request node’s retry settings.
Long email threads. Gmail sometimes returns entire conversation threads as the body. The 1500-character slice helps but you may still get irrelevant older content dominating the classification. Consider a preprocessing step that extracts only the most recent message — look for the last occurrence of “On [date], [person] wrote:” and take everything before it.
Mis-classification edge cases. Claude will occasionally classify a billing complaint as “support” or a cold outreach as “sales.” This isn’t a bug — the boundary is genuinely ambiguous. Don’t design downstream automations that take irreversible actions (like deleting) based solely on AI classification. Always route to a human-review label as fallback for anything destructive.
Token costs on forwarded emails. Emails with legal disclaimers, long signatures, or forwarded chains can easily hit 3000+ tokens. The slice helps, but consider a more aggressive preprocessing step that strips common footer patterns before sending to the API.
Extending the Workflow
Once the core n8n Claude workflow is stable, there are a few natural extensions worth building:
- Draft reply generation: For support emails, add a second Claude call to draft a first-pass reply that a human can review and send. This is where Sonnet earns its cost premium over Haiku.
- Sender context enrichment: Before calling Claude, look up the sender in your CRM (HubSpot, Attio, etc.) and inject that context into the prompt. “This sender is an existing customer on the Pro plan” changes the classification and urgency significantly.
- Daily digest summarization: Instead of real-time routing, batch low-urgency emails and send a single Slack digest each morning using Claude to summarize the batch.
Bottom Line: When to Use This Setup
Use this n8n Claude workflow if: you’re a solo founder or small team drowning in a mixed inbox, you want email routing that adapts to context rather than keyword matching, and you want to set it up once without maintaining a codebase.
Don’t use it if: you have strict data residency requirements (emails leave your infrastructure to hit Anthropic’s API), you need sub-second response times (5-minute polling plus API latency isn’t real-time), or your volume is high enough that per-call API costs become significant — above ~50,000 emails/month you’d want to evaluate fine-tuned models or batch classification pipelines.
For most teams operating under that threshold, the total infrastructure cost is a few dollars per month in API calls on top of whatever you’re paying for n8n. The time savings from not manually triaging email is worth it by the first week.
Editorial note: API pricing, model capabilities, and tool features change frequently — always verify current details on the vendor’s website before building in production. Code examples are tested at time of writing; pin your dependency versions to avoid breaking changes. Some links in this article may be affiliate links — we may earn a commission if you sign up, at no extra cost to you.

