{
  "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
          }
        ]
      ]
    }
  }
}