This workflow corresponds to n8n.io template #15366 — we link there as the canonical source.
This workflow follows the Gmail Trigger → Slack 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": "Support Inbox Router",
"tags": [],
"nodes": [
{
"id": "fc76d961-5ceb-4f54-9cf3-27a709b93cc1",
"name": "New Support Email",
"type": "n8n-nodes-base.gmailTrigger",
"position": [
-112,
208
],
"parameters": {
"simple": false,
"filters": {},
"options": {
"downloadAttachments": false
},
"pollTimes": {
"item": [
{
"mode": "everyMinute"
}
]
}
},
"typeVersion": 1
},
{
"id": "aa4e48cd-f983-4608-832e-a54838190a2e",
"name": "Route by Category",
"type": "n8n-nodes-base.switch",
"position": [
1248,
176
],
"parameters": {
"rules": {
"values": [
{
"conditions": {
"options": {
"version": 1,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "ccc6cbfd-6759-4227-8bfa-6943faf39289",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.data.category }}",
"rightValue": "billing"
}
]
}
},
{
"conditions": {
"options": {
"version": 1,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "d80d3596-0ffb-4100-9625-1945a4064a7b",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.data.category }}",
"rightValue": "technical"
}
]
}
},
{
"conditions": {
"options": {
"version": 1,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "88120474-c4f5-4850-bbef-2a6412ecc8ab",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.data.category }}",
"rightValue": "sales"
}
]
}
}
]
},
"options": {
"fallbackOutput": "extra",
"renameFallbackOutput": "other"
}
},
"typeVersion": 3
},
{
"id": "16b11847-6651-4d2e-829b-6b6283dac334",
"name": "Slack: Billing",
"type": "n8n-nodes-base.slack",
"position": [
1600,
0
],
"parameters": {
"text": "==:credit_card: {{ {\"urgent\": \"\ud83d\udea8\", \"normal\": \"\ud83d\udfe2\", \"low\": \"\u26aa\"}[$('easybits: Classify & Score Email').item.json.data.priority] }} *{{ $('easybits: Classify & Score Email').item.json.data.priority.toUpperCase() }} priority \u2014 billing*\n*From:* {{ $('New Support Email').item.json.from.value[0].address }}\n*Subject:* {{ $('New Support Email').item.json.subject }}\n*Summary:* {{ $('easybits: Classify & Score Email').item.json.data.summary }}\n*Confidence:* {{ $('easybits: Classify & Score Email').item.json.data.confidence }}",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "list",
"value": "",
"cachedResultName": ""
},
"otherOptions": {}
},
"typeVersion": 2.2
},
{
"id": "d6bf4180-b46c-4663-8785-e9aab75cd148",
"name": "Slack: Technical",
"type": "n8n-nodes-base.slack",
"position": [
1600,
160
],
"parameters": {
"text": "==:wrench: {{ {\"urgent\": \"\ud83d\udea8\", \"normal\": \"\ud83d\udfe2\", \"low\": \"\u26aa\"}[$('easybits: Classify & Score Email').item.json.data.priority] }} *{{ $('easybits: Classify & Score Email').item.json.data.priority.toUpperCase() }} priority \u2014 technical*\n*From:* {{ $('New Support Email').item.json.from.value[0].address }}\n*Subject:* {{ $('New Support Email').item.json.subject }}\n*Summary:* {{ $('easybits: Classify & Score Email').item.json.data.summary }}\n*Confidence:* {{ $('easybits: Classify & Score Email').item.json.data.confidence }}",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "list",
"value": "",
"cachedResultName": ""
},
"otherOptions": {}
},
"typeVersion": 2.2
},
{
"id": "5dfd9c45-b7ae-4cb0-8599-f50e10e887f1",
"name": "Slack: Sales",
"type": "n8n-nodes-base.slack",
"position": [
1600,
320
],
"parameters": {
"text": "==:briefcase: {{ {\"urgent\": \"\ud83d\udea8\", \"normal\": \"\ud83d\udfe2\", \"low\": \"\u26aa\"}[$('easybits: Classify & Score Email').item.json.data.priority] }} *{{ $('easybits: Classify & Score Email').item.json.data.priority.toUpperCase() }} priority \u2014 sales*\n*From:* {{ $('New Support Email').item.json.from.value[0].address }}\n*Subject:* {{ $('New Support Email').item.json.subject }}\n*Summary:* {{ $('easybits: Classify & Score Email').item.json.data.summary }}\n*Confidence:* {{ $('easybits: Classify & Score Email').item.json.data.confidence }}",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "list",
"value": "",
"cachedResultName": ""
},
"otherOptions": {}
},
"typeVersion": 2.2
},
{
"id": "d83b2eab-b2f0-461b-87e7-d4f60fd1a3d0",
"name": "Slack: Other",
"type": "n8n-nodes-base.slack",
"position": [
1600,
480
],
"parameters": {
"text": "==:inbox_tray: {{ {\"urgent\": \"\ud83d\udea8\", \"normal\": \"\ud83d\udfe2\", \"low\": \"\u26aa\"}[$('easybits: Classify & Score Email').item.json.data.priority] }} *{{ $('easybits: Classify & Score Email').item.json.data.priority.toUpperCase() }} priority \u2014 uncategorized*\n*From:* {{ $('New Support Email').item.json.from.value[0].address }}\n*Subject:* {{ $('New Support Email').item.json.subject }}\n*Summary:* {{ $('easybits: Classify & Score Email').item.json.data.summary }}\n*Confidence:* {{ $('easybits: Classify & Score Email').item.json.data.confidence }}{{ $('easybits: Classify & Score Email').item.json.data.confidence === 'low' ? ' \u26a0\ufe0f _Routed here due to low confidence \u2014 model\\'s best guess was: ' + $('easybits: Classify & Score Email').item.json.data.category + '_' : '' }}",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "list",
"value": "",
"cachedResultName": ""
},
"otherOptions": {}
},
"typeVersion": 2.2
},
{
"id": "03fbec4e-5b27-4455-bbd2-38b80838ac19",
"name": "easybits: Classify & Score Email",
"type": "@easybits/n8n-nodes-extractor.easybitsExtractor",
"position": [
560,
208
],
"parameters": {},
"typeVersion": 2
},
{
"id": "824c968c-a5f5-4820-8856-9b7a01c4a4d1",
"name": "Reroute Low Confidence to Other",
"type": "n8n-nodes-base.set",
"position": [
944,
208
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "1af5fc0c-e4b6-46e6-a434-4e8fd16b4bf1",
"name": "data.category",
"type": "string",
"value": "={{ $json.data.confidence === 'low' ? 'other' : $json.data.category }}"
}
]
},
"includeOtherFields": true
},
"typeVersion": 3.4
},
{
"id": "26675fb4-1990-44ca-80b0-8bf50fdb104a",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-208,
-48
],
"parameters": {
"color": 7,
"width": 288,
"height": 448,
"content": "## \ud83d\udce5 New Support Email\nPolls your support inbox for **new emails**. Set to **Every Minute** for testing \u2013 bump to Every 5 Minutes in production. Add a label filter (e.g. `support`) to keep personal mail out of the classifier."
},
"typeVersion": 1
},
{
"id": "3c8eb649-8f6f-4cc5-824d-a84f86ed21d0",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
96,
-48
],
"parameters": {
"color": 7,
"width": 288,
"height": 448,
"content": "## \ud83d\udcc4 Prepare Email for Extraction\nPackages the **email content** into a format that's ready to be processed by the Extractor pipeline. **Don't modify the code** \u2013 just paste it as-is. Handles long emails, weird characters, and missing fields safely."
},
"typeVersion": 1
},
{
"id": "53b109d9-f664-459b-b118-f80817e2ce16",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
400,
-48
],
"parameters": {
"color": 7,
"width": 432,
"height": 448,
"content": "## \ud83e\udd16 easybits: Classify & Score Email\nOne Extractor call returns four fields in a single pass:\n- **category** \u2192 billing / technical / sales / other\n- **summary** \u2192 1\u20132 sentence factual summary (in the email's language)\n- **confidence** \u2192 high / mid / low\n- **priority** \u2192 urgent / normal / low (sentiment + urgency)\n\nBilingual prompts handle **English and German** emails with the same rigor."
},
"typeVersion": 1
},
{
"id": "92142a6f-172d-430e-8c9f-bcbb77c28590",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
848,
-48
],
"parameters": {
"color": 7,
"width": 288,
"height": 448,
"content": "## \ud83d\udedf Reroute Low Confidence to Other\nSafety net step. If the Extractor returns **low confidence**, the category is rewritten to `other` so the email lands in the catch-all channel. The model's original best guess is preserved in the data and surfaced in the Slack message \u2013 useful for spotting prompts that need tuning."
},
"typeVersion": 1
},
{
"id": "d2a74013-e6b5-493a-bb7a-be516ab9a964",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
1152,
-48
],
"parameters": {
"color": 7,
"width": 288,
"height": 448,
"content": "## \ud83d\udd00 Route by Category\nReads the (possibly rewritten) `category` field and sends the email down one of four paths. The fallback output catches **any unmatched value** \u2013 including everything routed here by the low-confidence override."
},
"typeVersion": 1
},
{
"id": "6f0c7276-2413-485e-bdd2-895464a16dd6",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
1456,
-288
],
"parameters": {
"color": 7,
"width": 400,
"height": 944,
"content": "## \ud83d\udcac Slack: Per-Category Channels\nFour channels, one Slack node each. Every message includes:\n- Priority badge (\ud83d\udea8 / \ud83d\udfe2 / \u26aa) and label\n- Sender, subject, and 1\u20132 sentence summary\n- Confidence level\n- (For Other only) a breadcrumb showing the model's best guess if rerouted by low confidence\n\nReplace the channel field in each node with your real channel name or ID."
},
"typeVersion": 1
},
{
"id": "3e135580-905b-4bc9-b0d3-7da730ec6890",
"name": "Sticky Note6",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1056,
-624
],
"parameters": {
"width": 832,
"height": 1648,
"content": "# \ud83d\udcec Support Inbox Router\n(powered by easybits)\n\n## What This Workflow Does\nWatches your support inbox, classifies every incoming email by category, scores it for **priority** based on sentiment and urgency signals, and posts a clean summary to the matching Slack channel. Works equally well for **English and German** emails. Low-confidence classifications automatically fall through to the catch-all channel so nothing slips through, with the model's best guess preserved as a breadcrumb.\n\n## How It Works\n1. **Watch** \u2013 Gmail Trigger polls your support inbox for new mail\n2. **Prepare** \u2013 The email content is packaged into a format ready for extraction\n3. **Classify** \u2013 easybits returns category, summary, confidence, and priority in one call\n4. **Route** \u2013 Low-confidence emails are folded into \"Other\"; the rest go by category\n5. **Notify** \u2013 A formatted message lands in the matching Slack channel with priority emoji\n\n## Categories\n- \ud83d\udcb3 **Billing** \u2013 invoices, payments, refunds, subscription changes\n- \ud83d\udd27 **Technical** \u2013 bug reports, errors, login issues\n- \ud83d\udcbc **Sales** \u2013 pricing questions, demo requests, new prospects\n- \ud83d\udce5 **Other** \u2013 everything else, plus low-confidence fallbacks\n\n## Priority Levels\n- \ud83d\udea8 **Urgent** \u2013 angry tone, things broken, hot leads, time-sensitive\n- \ud83d\udfe2 **Normal** \u2013 standard requests, no time pressure\n- \u26aa **Low** \u2013 casual inquiries, FYIs, vendor pitches\n\n## Setup Guide\n### 1. Install the easybits Extractor Node\nAlready available out of the box on **n8n Cloud**. On self-hosted instances: Settings \u2192 Community Nodes \u2192 Install `@easybits/n8n-nodes-extractor`.\n\n### 2. Connect Your Credentials\n- **Gmail** on the trigger node (OAuth)\n- **easybits** on the classify node (API key from easybits.tech)\n- **Slack** on all four channel nodes (one credential, reused four times)\n\n### 3. Set Up the Extractor Pipeline\nCreate an easybits pipeline with four fields. Copy each prompt below into the matching field's description:\n\n- \ud83d\udcc2 [Category Classification Prompt](https://github.com/felix-sattler-easybits/n8n-workflows/blob/a62d2189ed8ee72424335454fdf82fc735c2b14a/easybits-support-inbox-router/easybits_category_classification_prompt.md)\n- \ud83d\udcdd [Summary Prompt](https://github.com/felix-sattler-easybits/n8n-workflows/blob/a62d2189ed8ee72424335454fdf82fc735c2b14a/easybits-support-inbox-router/easybits_summary_prompt.md)\n- \ud83c\udfaf [Confidence Prompt](https://github.com/felix-sattler-easybits/n8n-workflows/blob/a62d2189ed8ee72424335454fdf82fc735c2b14a/easybits-support-inbox-router/easybits_confidence_prompt.md)\n- \ud83d\udea6 [Priority Prompt](https://github.com/felix-sattler-easybits/n8n-workflows/blob/a62d2189ed8ee72424335454fdf82fc735c2b14a/easybits-support-inbox-router/easybits_priority_prompt.md)\n\n### 4. Set Up Slack Channels\nCreate four channels in your workspace and update each Slack node to point at the right one:\n- `#support-billing`\n- `#support-technical`\n- `#support-sales`\n- `#support-other`\n\n### 5. (Optional) Filter the Inbox\nOn the Gmail Trigger, add a label filter (e.g. `support`) so personal mail doesn't get classified.\n\n### 6. Activate & Test\nSend a few test emails covering different categories and tones. Verify they land in the right channels with sensible priority emoji before going live.\n\n## Notes\n- **Bilingual prompt** \u2013 works on English and German emails out of the box, with German summaries for German emails\n- **No confidence gate** \u2013 low-confidence emails route to `#support-other` with a flag noting the model's best guess, so reviewers can spot patterns without a separate channel\n- **One Extractor call** \u2013 classification, summary, confidence, and priority all come from a single pipeline call, keeping latency and cost low"
},
"typeVersion": 1
},
{
"id": "752bc6ba-a2f5-4313-ae1c-9e1678f9e4f3",
"name": "Prepare Email",
"type": "n8n-nodes-base.code",
"position": [
176,
208
],
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "// Packages the incoming email into a format that the easybits Extractor can read.\n// You don't need to understand or modify this \u2014 just paste it as-is.\n\nconst email = $input.item.json;\n\n// Pull the fields out of the Gmail node, with safe fallbacks\nconst subject = email.subject || '(no subject)';\nconst from = email.from?.value?.[0]?.address || email.from?.text || 'unknown sender';\nconst date = email.date || '';\nconst body = email.text || email.snippet || '(empty body)';\n\n// Build the document content\nconst content = `Subject: ${subject}\nFrom: ${from}\nDate: ${date}\n\n${body}`;\n\n// Escape characters that have special meaning in PDFs\nconst escape = (s) => s.replace(/\\\\/g, '\\\\\\\\').replace(/\\(/g, '\\\\(').replace(/\\)/g, '\\\\)');\n\n// Wrap long lines so they fit on the page\nconst lines = content.split('\\n').flatMap((line) => {\n if (line.length === 0) return [''];\n const wrapped = [];\n for (let i = 0; i < line.length; i += 90) {\n wrapped.push(line.slice(i, i + 90));\n }\n return wrapped;\n});\n\n// Build the text stream that the PDF will render\nlet stream = 'BT\\n/F1 10 Tf\\n50 780 Td\\n12 TL\\n';\nfor (const line of lines) {\n stream += `(${escape(line)}) Tj\\nT*\\n`;\n}\nstream += 'ET';\n\nconst streamLength = Buffer.byteLength(stream, 'utf-8');\n\n// Assemble the PDF structure\nconst objects = [\n '1 0 obj << /Type /Catalog /Pages 2 0 R >> endobj',\n '2 0 obj << /Type /Pages /Kids [3 0 R] /Count 1 >> endobj',\n '3 0 obj << /Type /Page /Parent 2 0 R /MediaBox [0 0 612 792] /Contents 4 0 R /Resources << /Font << /F1 5 0 R >> >> >> endobj',\n `4 0 obj << /Length ${streamLength} >> stream\\n${stream}\\nendstream endobj`,\n '5 0 obj << /Type /Font /Subtype /Type1 /BaseFont /Helvetica >> endobj',\n];\n\n// Calculate byte offsets for the cross-reference table\nconst header = '%PDF-1.4\\n';\nconst offsets = [0];\nlet cursor = Buffer.byteLength(header, 'utf-8');\nfor (const obj of objects) {\n offsets.push(cursor);\n cursor += Buffer.byteLength(obj + '\\n', 'utf-8');\n}\n\n// Build the xref table\nlet xref = `xref\\n0 ${objects.length + 1}\\n+1234567890 f \\n`;\nfor (let i = 1; i <= objects.length; i++) {\n xref += `${offsets[i].toString().padStart(10, '0')} 00000 n \\n`;\n}\n\nconst trailer = `trailer << /Size ${objects.length + 1} /Root 1 0 R >>\\nstartxref\\n${cursor}\\n%%EOF`;\n\nconst pdf = header + objects.join('\\n') + '\\n' + xref + trailer;\n\n// Hand the document off to the next node as a binary file\nreturn {\n json: { subject, from, date },\n binary: {\n data: {\n data: Buffer.from(pdf, 'binary').toString('base64'),\n mimeType: 'application/pdf',\n fileName: 'email.pdf',\n },\n },\n};"
},
"typeVersion": 2
}
],
"active": false,
"settings": {
"executionOrder": "v1"
},
"connections": {
"Prepare Email": {
"main": [
[
{
"node": "easybits: Classify & Score Email",
"type": "main",
"index": 0
}
]
]
},
"New Support Email": {
"main": [
[
{
"node": "Prepare Email",
"type": "main",
"index": 0
}
]
]
},
"Route by Category": {
"main": [
[
{
"node": "Slack: Billing",
"type": "main",
"index": 0
}
],
[
{
"node": "Slack: Technical",
"type": "main",
"index": 0
}
],
[
{
"node": "Slack: Sales",
"type": "main",
"index": 0
}
],
[
{
"node": "Slack: Other",
"type": "main",
"index": 0
}
]
]
},
"Reroute Low Confidence to Other": {
"main": [
[
{
"node": "Route by Category",
"type": "main",
"index": 0
}
]
]
},
"easybits: Classify & Score Email": {
"main": [
[
{
"node": "Reroute Low Confidence to Other",
"type": "main",
"index": 0
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Watches your support inbox, classifies every incoming email by category, scores it for priority based on sentiment and urgency signals, and posts a clean summary to the matching Slack channel. Works equally well for English and German emails. Low-confidence classifications…
Source: https://n8n.io/workflows/15366/ — 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.
Receive any business document via email. The attachment is automatically classified (Invoice, Contract, or Purchase Order) using easybits Extractor, then routed down the correct path where a second Ex
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
Automatically convert Gmail emails and Slack messages into Zendesk support tickets with intelligent priority detection, comprehensive Google Sheets tracking, and real-time team notifications. Streamli
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
📘 Description