This workflow follows the Chainllm → Gmail recipe pattern — see all workflows that pair these two integrations.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"name": "NTF 03: Email Triage Agent",
"tags": [
{
"name": "NTF-Playbook"
}
],
"settings": {
"executionOrder": "v1"
},
"nodes": [
{
"id": "sticky-readme",
"name": "README",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
-60,
-520
],
"parameters": {
"content": "## NTF 03: Email Triage Agent\n\n**Trigger:** Gmail polling every 5 minutes (unread, inbox)\n\n**Flow:**\n1. Poll Gmail for unread emails\n2. Extract sender, subject, body\n3. Claude classifies category and drafts reply\n4. Create Gmail draft (ready to review)\n5. If priority is high, also send a Slack ping\n\n**Setup:**\n- Connect Gmail OAuth credential (read + draft + modify scopes only)\n- Set your Slack channel id for urgent alerts\n- Edit the Claude prompt categories to match your inbox types\n- Note: this template does not auto-mark emails as read or apply a label. Add an `addLabel` step downstream if you want once-only processing.",
"height": 380,
"width": 540,
"color": 6
}
},
{
"id": "gmail-trigger",
"name": "Gmail Poll Unread",
"type": "n8n-nodes-base.gmailTrigger",
"typeVersion": 1.2,
"position": [
0,
0
],
"parameters": {
"pollTimes": {
"item": [
{
"mode": "everyX",
"value": 5,
"unit": "minutes"
}
]
},
"filters": {
"readStatus": "unread",
"includeSpamTrash": false
}
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
}
},
{
"id": "extract-email",
"name": "Extract Email Fields",
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
220,
0
],
"parameters": {
"mode": "manual",
"assignments": {
"assignments": [
{
"id": "email_id",
"name": "email_id",
"value": "={{ $json.id }}",
"type": "string"
},
{
"id": "from",
"name": "from",
"value": "={{ $json.from }}",
"type": "string"
},
{
"id": "subject",
"name": "subject",
"value": "={{ $json.subject }}",
"type": "string"
},
{
"id": "body",
"name": "body",
"value": "={{ $json.text || $json.snippet || '' }}",
"type": "string"
},
{
"id": "date",
"name": "date",
"value": "={{ $json.date }}",
"type": "string"
}
]
}
}
},
{
"id": "claude-llm",
"name": "Claude Triage Model",
"type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
"typeVersion": 1.3,
"position": [
440,
0
],
"parameters": {
"model": "claude-haiku-4-5-20251001",
"options": {
"maxTokens": 800
}
},
"credentials": {
"anthropicApi": {
"name": "<your credential>"
}
}
},
{
"id": "triage-chain",
"name": "Triage + Draft Reply",
"type": "@n8n/n8n-nodes-langchain.chainLlm",
"typeVersion": 1.4,
"position": [
440,
0
],
"parameters": {
"promptType": "define",
"text": "=You are an email triage assistant. Analyze this email and return a JSON object with:\n- category: one of \"support\", \"billing\", \"sales_inquiry\", \"partnership\", \"spam\", \"personal\", \"urgent\", \"newsletter\", \"other\"\n- priority: \"high\" | \"medium\" | \"low\"\n- one_line_summary: max 15 words describing what the email is about\n- draft_reply: a short, professional reply draft (2-4 sentences). Write in first person as the business owner. Leave [PLACEHOLDER] where personalization is needed.\n- label: the Gmail label to apply, same as category\n\nEmail:\nFrom: {{ $('Extract Email Fields').item.json.from }}\nSubject: {{ $('Extract Email Fields').item.json.subject }}\nBody: {{ $('Extract Email Fields').item.json.body }}\n\nReturn only valid JSON, no markdown fencing."
}
},
{
"id": "parse-triage",
"name": "Parse Triage Response",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
660,
0
],
"parameters": {
"jsCode": "const raw = $input.first().json.text || '{}';\nlet parsed = {};\ntry {\n parsed = JSON.parse(raw.replace(/```json|```/g, '').trim());\n} catch(e) {\n parsed = { category: 'other', priority: 'medium', one_line_summary: 'Parse error', draft_reply: '', label: 'other' };\n}\nconst prev = $('Extract Email Fields').first().json;\nreturn [{ json: { ...prev, ...parsed } }];"
}
},
{
"id": "gmail-draft",
"name": "Create Gmail Draft",
"type": "n8n-nodes-base.gmail",
"typeVersion": 2.1,
"position": [
880,
-120
],
"parameters": {
"operation": "createDraft",
"sendTo": "={{ $json.from }}",
"subject": "=Re: {{ $json.subject }}",
"message": "={{ $json.draft_reply }}",
"options": {}
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
}
},
{
"id": "check-urgent",
"name": "Is Urgent?",
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
880,
80
],
"parameters": {
"conditions": {
"options": {
"caseSensitive": false
},
"conditions": [
{
"id": "priority-check",
"leftValue": "={{ $json.priority }}",
"rightValue": "high",
"operator": {
"type": "string",
"operation": "equals"
}
}
]
}
}
},
{
"id": "slack-urgent",
"name": "Slack Urgent Alert",
"type": "n8n-nodes-base.slack",
"typeVersion": 2.3,
"position": [
1100,
0
],
"parameters": {
"operation": "post",
"channel": "YOUR_SLACK_CHANNEL_ID",
"text": "=*Urgent email needs your attention*\n*From:* {{ $json.from }}\n*Subject:* {{ $json.subject }}\n*Summary:* {{ $json.one_line_summary }}\n*Category:* {{ $json.category }}\n\nDraft reply is ready in Gmail."
},
"credentials": {
"slackApi": {
"name": "<your credential>"
}
}
}
],
"connections": {
"Gmail Poll Unread": {
"main": [
[
{
"node": "Extract Email Fields",
"type": "main",
"index": 0
}
]
]
},
"Extract Email Fields": {
"main": [
[
{
"node": "Triage + Draft Reply",
"type": "main",
"index": 0
}
]
]
},
"Claude Triage Model": {
"ai_languageModel": [
[
{
"node": "Triage + Draft Reply",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Triage + Draft Reply": {
"main": [
[
{
"node": "Parse Triage Response",
"type": "main",
"index": 0
}
]
]
},
"Parse Triage Response": {
"main": [
[
{
"node": "Create Gmail Draft",
"type": "main",
"index": 0
},
{
"node": "Is Urgent?",
"type": "main",
"index": 0
}
]
]
},
"Is Urgent?": {
"main": [
[
{
"node": "Slack Urgent Alert",
"type": "main",
"index": 0
}
],
[]
]
}
}
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
anthropicApigmailOAuth2slackApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
NTF 03: Email Triage Agent. Uses gmailTrigger, lmChatAnthropic, chainLlm, gmail. Event-driven trigger; 9 nodes.
Source: https://github.com/MinaSaad1/n8n-email-triage/blob/main/workflows/01-email-triage.json — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
This workflow contains community nodes that are only compatible with the self-hosted version of n8n.
This n8n template shows you how to automate customer support email triage with a sovereign AI. By combining Gmail for inbox monitoring and the IONOS AI Model Hub, every customer email is classified an
Professionals and individuals who receive high volumes of emails, those who want to automatically organize their Gmail inbox using AI classification.
This template is built to be customized for your specific needs. This template has the core logic and n8n node specific references sorted to work with dynamic file names throughout the workflow. Store
This is an elite enterprise-grade solution for Talent Acquisition and HR Ops teams. It automates the high-volume task of resume screening by transforming unstructured PDF applications into structured