AutomationFlowsAI & RAG › Triage Vip Outlook Emails Using Excel, Gpt-4o and Microsoft to Do

Triage Vip Outlook Emails Using Excel, Gpt-4o and Microsoft to Do

ByMychel Garzon @mychel-garzon on n8n.io

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.…

Event trigger★★★★☆ complexityAI-powered17 nodesMicrosoft Outlook TriggerMicrosoft ExcelOpenAIMicrosoft To DoError TriggerMicrosoft Outlook
AI & RAG Trigger: Event Nodes: 17 Complexity: ★★★★☆ AI nodes: yes Added:

This workflow corresponds to n8n.io template #15895 — we link there as the canonical source.

This workflow follows the Error Trigger → OpenAI 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 →

Download .json
{
  "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
          }
        ]
      ]
    }
  }
}
Pro

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 →

More AI & RAG workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

AI & RAG

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

Microsoft Outlook Trigger, OpenAI, Microsoft SharePoint +3
AI & RAG

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

Microsoft Outlook, Microsoft One Drive, Microsoft Excel +2
AI & RAG

Analyze incoming support requests, classify intent and priority with AI, create Jira tickets, assign the correct team, send Slack notifications, and track SLA deadlines. Supports Gmail, WhatsApp, form

Gmail Trigger, HTTP Request, Form Trigger +4
AI & RAG

Complete AI-powered sales system Automates lead capture, qualification, and follow-up from multiple channels. AI INTELLIGENCE:

Gmail Trigger, Google Sheets, OpenAI +3
AI & RAG

Transcript Audio To Text. Uses googleDocs, googleDrive, openAi, gmail. Event-driven trigger; 31 nodes.

Google Docs, Google Drive, OpenAI +7