This workflow corresponds to n8n.io template #15895 — we link there as the canonical source.
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 →
{
"id": "B98tGo6NVT2gTCOY",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Outlook Email Triage: AI Urgency Detection with Automatic Task Creation",
"tags": [],
"nodes": [
{
"id": "0c76aca6-d474-4e13-b65a-2410fa4a739b",
"name": "Outlook Trigger",
"type": "n8n-nodes-base.microsoftOutlookTrigger",
"position": [
3984,
1264
],
"parameters": {
"filters": {},
"options": {},
"pollTimes": {
"item": [
{
"mode": "everyX",
"unit": "minutes",
"value": 5
}
]
}
},
"typeVersion": 1
},
{
"id": "f31b34ae-25df-4949-a7f8-77ac05d7cdce",
"name": "Deduplicate Threads",
"type": "n8n-nodes-base.code",
"position": [
4208,
1264
],
"parameters": {
"jsCode": "const staticData = $getWorkflowStaticData('global');\nstaticData.processedIds = staticData.processedIds || [];\n\nconst newItems = [];\nfor (const item of $input.all()) {\n const msgId = item.json.conversationId || item.json.id;\n if (!staticData.processedIds.includes(msgId)) {\n newItems.push(item);\n staticData.processedIds.push(msgId);\n }\n}\n\nif (staticData.processedIds.length > 100) {\n staticData.processedIds = staticData.processedIds.slice(-100);\n}\n\nreturn newItems;"
},
"typeVersion": 2
},
{
"id": "2d317fcf-2857-464c-bbfc-1357607c0507",
"name": "Excel: Read VIP Sheet",
"type": "n8n-nodes-base.microsoftExcel",
"position": [
4448,
1264
],
"parameters": {
"operation": "readRows"
},
"typeVersion": 1
},
{
"id": "f9fcb080-e2dc-471d-9a7e-a97a32b494a5",
"name": "Code: Tag & Filter VIPs",
"type": "n8n-nodes-base.code",
"position": [
4656,
1264
],
"parameters": {
"jsCode": "// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n// OPTION A: Single-read VIP check\n//\n// $input.all() \u2192 rows from the Excel sheet (one item per row)\n// $node[\"Deduplicate Threads\"].all() \u2192 the deduplicated email batch\n//\n// Strategy:\n// 1. Build a Set of VIP email addresses from the sheet (O(1) lookup).\n// 2. Loop through the email batch and tag each item with isVip: true/false.\n// 3. Return ONLY the VIP-tagged emails so the downstream pipeline is unchanged.\n//\n// This replaces both the old \"Excel: VIP Lookup\" (per-item) node AND the\n// old \"Is VIP?\" IF node -- one API call, zero rate-limit risk.\n// \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\n// Step 1: Build the VIP Set from the sheet rows.\n// \u26a0\ufe0f ACTION REQUIRED: Change 'email' below to match your actual column header.\nconst VIP_COLUMN = 'email';\n\nconst vipSet = new Set(\n $input.all()\n .map(row => (row.json[VIP_COLUMN] || '').toString().toLowerCase().trim())\n .filter(Boolean)\n);\n\n// Step 2: Grab the email batch from the upstream Deduplicate node.\nconst emails = $node[\"Deduplicate Threads\"].all();\n\nif (!emails || emails.length === 0) {\n // Nothing to process -- stop cleanly.\n return [];\n}\n\n// Step 3: Tag each email and keep only VIPs.\nconst vipEmails = emails\n .map(item => {\n const senderAddress = (item.json?.from?.emailAddress?.address || '').toLowerCase().trim();\n return {\n json: {\n ...item.json,\n isVip: vipSet.has(senderAddress)\n }\n };\n })\n .filter(item => item.json.isVip);\n\nreturn vipEmails;"
},
"typeVersion": 2
},
{
"id": "f368d7ec-e688-47ea-89df-b42111065dad",
"name": "Strip HTML Bloat",
"type": "n8n-nodes-base.html",
"position": [
4880,
1264
],
"parameters": {
"options": {},
"operation": "extractHtmlContent",
"sourceData": "html",
"extractionValues": {
"values": [
{
"key": "plainTextBody",
"cssSelector": "body"
}
]
}
},
"typeVersion": 1
},
{
"id": "33a91000-9cc9-4398-9970-4e29a8ae27b0",
"name": "AI: Analyze Urgency",
"type": "n8n-nodes-base.openAi",
"position": [
5104,
1264
],
"parameters": {
"model": "gpt-4o",
"options": {},
"requestOptions": {}
},
"typeVersion": 1
},
{
"id": "00fdd489-8723-4d2a-b7fb-135943319c20",
"name": "Parse AI Output",
"type": "n8n-nodes-base.code",
"position": [
5328,
1264
],
"parameters": {
"jsCode": "return $input.all().map(item => {\n let aiData = { is_urgent: false, summary: \"Parsing failed.\" };\n try {\n let raw = item.json.aiAnalysis?.message?.content || \"{}\";\n let clean = raw.replace(/```json/g, '').replace(/```/g, '').trim();\n aiData = JSON.parse(clean);\n } catch (e) {}\n\n return {\n json: {\n ...item.json,\n is_urgent: aiData.is_urgent ?? false,\n summary: aiData.summary ?? \"Parsing failed.\"\n }\n };\n});"
},
"typeVersion": 2
},
{
"id": "dcf4fcfb-ff13-4adf-a7a5-9497226277db",
"name": "Is Urgent?",
"type": "n8n-nodes-base.if",
"position": [
5552,
1264
],
"parameters": {
"conditions": {
"boolean": [
{
"value1": "={{ $json.is_urgent }}",
"value2": true
}
]
}
},
"typeVersion": 1
},
{
"id": "c0af2992-34b6-4ea4-8537-712e02223236",
"name": "Create VIP To Do Task",
"type": "n8n-nodes-base.microsoftToDo",
"position": [
5776,
1248
],
"parameters": {
"title": "={{ '\ud83d\udea8 VIP Escalation: ' + $json.from.emailAddress.name + ' - ' + $json.subject }}",
"operation": "create",
"additionalFields": {}
},
"typeVersion": 1
},
{
"id": "84173b9a-833f-47cb-a5c6-ffbb405de2ae",
"name": "Error Trigger",
"type": "n8n-nodes-base.errorTrigger",
"position": [
3968,
1568
],
"parameters": {},
"typeVersion": 1
},
{
"id": "2143c8ca-7b57-451b-a44e-46778309ce14",
"name": "Send Error Email",
"type": "n8n-nodes-base.microsoftOutlook",
"position": [
4208,
1568
],
"parameters": {
"subject": "\ud83d\udea8 n8n Workflow Error: VIP Triage",
"toRecipients": [
"user@example.com"
],
"additionalFields": {}
},
"typeVersion": 2
},
{
"id": "fb09f673-8ec4-42a9-8420-26c3e29f8c46",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
3440,
1120
],
"parameters": {
"width": 464,
"height": 592,
"content": "## Outlook Email Triage: AI Urgency Detection with Automatic Task Creation\n\n### AI-Powered Outlook Monitoring with Microsoft To Do Escalation\n\n### How it works\nThis workflow polls your Outlook inbox every 5 minutes, filters emails from priority senders stored in an Excel sheet, analyzes urgency with GPT-4o, and automatically creates a Microsoft To Do task for any message that needs immediate attention.\n\n### Required credentials\n- **Microsoft Outlook OAuth2** (trigger + error email)\n- **Microsoft Excel** (priority sender list read)\n- **OpenAI API** (urgency analysis via GPT-4o)\n- **Microsoft To Do** (task creation)\n\n### Excel sheet structure expected\nOne column containing priority sender email addresses. Default column header: `email`"
},
"typeVersion": 1
},
{
"id": "f06d6808-42af-46a7-ae94-2b62f6e83ea9",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
3936,
1120
],
"parameters": {
"color": 7,
"width": 416,
"height": 304,
"content": "### Trigger & Deduplication\nPolls Outlook every 5 minutes for new emails and filters out any conversation threads already processed in a previous run using in-memory static data."
},
"typeVersion": 1
},
{
"id": "a6ce05d1-f160-442d-a130-7b823e0c6618",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
4384,
1120
],
"parameters": {
"color": 7,
"width": 432,
"height": 304,
"content": "### VIP Lookup & Filtering\nReads the full VIP list from Excel in a single batch, builds a fast lookup set, and filters the email batch down to VIP senders only."
},
"typeVersion": 1
},
{
"id": "5e4274be-ca5b-43ed-a1a0-3a447cb250e3",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
4848,
1120
],
"parameters": {
"color": 7,
"width": 624,
"height": 304,
"content": "### AI Urgency Analysis\nStrips HTML markup from the email body, passes the clean text to GPT-4o for\nurgency classification, and parses the structured JSON output for downstream use."
},
"typeVersion": 1
},
{
"id": "1748133e-34d5-426b-b44a-3d4fd06c7685",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
3936,
1456
],
"parameters": {
"color": 7,
"width": 544,
"height": 256,
"content": "### Error Handling\nGlobal error catcher that intercepts any node failure and sends an alert\nemail to the configured admin address with the workflow error details."
},
"typeVersion": 1
},
{
"id": "998d8ab6-6704-49ba-962b-c45c15c1082c",
"name": "Sticky Note6",
"type": "n8n-nodes-base.stickyNote",
"position": [
5504,
1120
],
"parameters": {
"color": 7,
"width": 496,
"height": 304,
"content": "### Escalation & Task Creation\nRoutes urgent VIP emails to Microsoft To Do, creating a flagged task with the sender name and subject. Non-urgent emails exit silently."
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"binaryMode": "separate",
"executionOrder": "v1"
},
"versionId": "6f83ba52-472a-4928-ae59-47f21af71e48",
"connections": {
"Is Urgent?": {
"main": [
[
{
"node": "Create VIP To Do Task",
"type": "main",
"index": 0
}
]
]
},
"Error Trigger": {
"main": [
[
{
"node": "Send Error Email",
"type": "main",
"index": 0
}
]
]
},
"Outlook Trigger": {
"main": [
[
{
"node": "Deduplicate Threads",
"type": "main",
"index": 0
}
]
]
},
"Parse AI Output": {
"main": [
[
{
"node": "Is Urgent?",
"type": "main",
"index": 0
}
]
]
},
"Strip HTML Bloat": {
"main": [
[
{
"node": "AI: Analyze Urgency",
"type": "main",
"index": 0
}
]
]
},
"AI: Analyze Urgency": {
"main": [
[
{
"node": "Parse AI Output",
"type": "main",
"index": 0
}
]
]
},
"Deduplicate Threads": {
"main": [
[
{
"node": "Excel: Read VIP Sheet",
"type": "main",
"index": 0
}
]
]
},
"Excel: Read VIP Sheet": {
"main": [
[
{
"node": "Code: Tag & Filter VIPs",
"type": "main",
"index": 0
}
]
]
},
"Code: Tag & Filter VIPs": {
"main": [
[
{
"node": "Strip HTML Bloat",
"type": "main",
"index": 0
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow polls Microsoft Outlook every 5 minutes, deduplicates email threads, checks senders against a VIP list in Microsoft Excel, uses OpenAI (GPT-4o) to detect urgency, and creates a Microsoft To Do task for urgent VIP emails while emailing an admin on workflow errors.…
Source: https://n8n.io/workflows/15895/ — 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 polls Outlook for meeting summary emails, uses GPT-4o to extract strategic decisions and action items from the transcript, logs decisions to a SharePoint list, creates Microsoft To Do ta
This workflow watches your Outlook inbox, automatically downloads file attachments (for example invoices), saves them into a specific OneDrive folder, and logs each file name into an Excel table. Opti
Complete AI-powered sales system Automates lead capture, qualification, and follow-up from multiple channels. AI INTELLIGENCE:
Transcript Audio To Text. Uses googleDocs, googleDrive, openAi, gmail. Event-driven trigger; 31 nodes.
This workflow is an AI-powered lighting and look development pipeline designed for VFX production. It transforms a single lighting brief into multiple high-quality cinematic lighting references using