{
  "nodes": [
    {
      "id": "ad82d0b6-3eda-41c6-9f41-e18351dd0798",
      "name": "Template Header",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -496,
        112
      ],
      "parameters": {
        "color": 4,
        "width": 542,
        "height": 498,
        "content": "## \ud83e\udd16 AI Email Support Agent with RAG\n\n**Overview**\nThis workflow automates email responses by combining CRM data (Supabase) with technical knowledge (Vector Store) to draft accurate, personalized replies in Outlook.\n\n**Requirements**\n- **Microsoft Outlook** (Business Account)\n- **Supabase** (Postgres DB & Vector Store)\n- **OpenAI** (API Key for GPT-4o & Embeddings)\n- **Google Sheets** (For logging)\n\n**Setup Instructions**\n1. **Credentials**: Connect your Outlook, OpenAI, Supabase, and Google accounts.\n2. **Supabase**: Ensure you have a 'contacts' table and a Vector Store set up for your product manuals.\n3. **Placeholders**: Update the **Green** nodes with your specific IDs (Sheet ID, Table Name, etc.).\n4. **Code Node**: Update the 'Business Rules' and Persona details in the 'Build AI Prompt' node."
      },
      "typeVersion": 1
    },
    {
      "id": "bbab8f96-a08c-4a19-b6c9-a1d406ab3ecc",
      "name": "Context Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        384,
        80
      ],
      "parameters": {
        "color": 6,
        "width": 360,
        "height": 140,
        "content": "### 1. Context Building\nWe trigger on new emails, then immediately look up the sender in our Supabase CRM to get their Name, Role, and Department. This allows the AI to personalize the greeting."
      },
      "typeVersion": 1
    },
    {
      "id": "c6fdb366-2567-4c91-93f9-2f436b7e71a8",
      "name": "AI Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1360,
        96
      ],
      "parameters": {
        "color": 6,
        "width": 380,
        "height": 140,
        "content": "### 2. AI Reasoning (RAG)\nThe Agent uses **GPT-4o** to analyze the email intent. It utilizes the **Vector Store Tool** to look up technical answers from your documentation before formulating a reply."
      },
      "typeVersion": 1
    },
    {
      "id": "944780a6-03f4-4655-848f-7404c5b9c5e7",
      "name": "On Email Received",
      "type": "n8n-nodes-base.microsoftOutlookTrigger",
      "position": [
        128,
        288
      ],
      "parameters": {
        "filters": {},
        "options": {},
        "pollTimes": {
          "item": [
            {
              "mode": "everyMinute"
            }
          ]
        }
      },
      "typeVersion": 1
    },
    {
      "id": "21d513a5-ec79-4c56-8bbc-c2731f3976e8",
      "name": "Config Variables",
      "type": "n8n-nodes-base.set",
      "position": [
        352,
        288
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": []
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "b8f7e691-6959-40aa-a534-1652c2933a86",
      "name": "Draft Outlook Reply",
      "type": "n8n-nodes-base.microsoftOutlook",
      "position": [
        1568,
        288
      ],
      "parameters": {
        "subject": "=RE: {{ $('On Email Received').first().json.subject }}",
        "resource": "draft",
        "bodyContent": "={{ $json.reply_html }}",
        "additionalFields": {
          "toRecipients": "={{ $('On Email Received').first().json.from }}",
          "bodyContentType": "html"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "14ab319b-032d-4d4b-851c-6887c9b8ee89",
      "name": "Log to Google Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1792,
        288
      ],
      "parameters": {
        "columns": {
          "value": {
            "From": "={{ $('On Email Received').first().json.from }}",
            "Status": "Success",
            "Product": "={{ $('AI Support Agent').first().json.primary_product_codes[0] || '' }}",
            "Urgency": "={{ $('AI Support Agent').first().json.urgency }}",
            "Timestamp": "={{ $now.toISO() }}",
            "Department": "={{ $('AI Support Agent').first().json.department }}",
            "Email Subject": "={{ $('On Email Received').first().json.subject }}"
          },
          "schema": [
            {
              "id": "Status",
              "required": false,
              "displayName": "Status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Email Subject",
              "required": false,
              "displayName": "Email Subject",
              "defaultMatch": true,
              "canBeUsedToMatch": true
            },
            {
              "id": "From",
              "required": false,
              "displayName": "From",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Department",
              "required": false,
              "displayName": "Department",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Product",
              "required": false,
              "displayName": "Product",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Urgency",
              "required": false,
              "displayName": "Urgency",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Timestamp",
              "required": false,
              "displayName": "Timestamp",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "Email Subject"
          ]
        },
        "options": {},
        "operation": "appendOrUpdate",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "<__PLACEHOLDER_VALUE__SHEET_NAME__>"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "<__PLACEHOLDER_VALUE__GOOGLE_SHEET_ID__>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "5260b615-7c6d-46c3-b140-badf6563cbe9",
      "name": "AI Support Agent",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        1056,
        288
      ],
      "parameters": {
        "text": "={{ $json.chatInput }}",
        "options": {
          "systemMessage": "=You act as [YOUR_AGENT_NAME], [YOUR_JOB_TITLE] for [YOUR_COMPANY_NAME] supplying [YOUR_PRODUCT_TYPE].\n\nYou get inbound emails from customers/clients. You have sender info (name, company, department, role) and a vector store of manuals/specs/how-to guides/marketing docs/case studies.\n\nTasks:\n1) From the input, decide:\n   - intent: \"technical_question\" | \"pricing_request\" | \"internal_quote_email\" | \"generic_enquiry\"\n   - primary_product_codes: array of product codes mentioned (may be empty)\n   - urgency: \"high\" | \"normal\" | \"low\"\n   - department: best-guess department name\n\n2) Use the vector store tool only to retrieve relevant info for that department and those products.\n\n3) Draft a short, clear reply email as [YOUR_AGENT_NAME] that:\n   - Answers the question using retrieved context where useful\n   - Optionally and softly suggests relevant accessories or trials (no hard sell)\n   - Uses appropriate regional spelling (e.g., UK or US) and a professional tone\n   - Is max 2-3 short paragraphs plus optional bullets\n   - Starts with \"Hi {first_name},\" and ends with:\n     \"Kind regards,\n      [YOUR_AGENT_NAME]\n      [YOUR_JOB_TITLE]\"\n\n4) Never provide emergency advice. If unsure, say you will check and follow up.\n\nReturn a single JSON object ONLY:\n{\n  \"reply_html\": \"<html>\u2026full email body in HTML\u2026</html>\",\n  \"intent\": \"technical_question\",\n  \"primary_product_codes\": [\"...\"],\n  \"urgency\": \"normal\",\n  \"department\": \"Ophthalmology\"\n}"
        },
        "promptType": "define"
      },
      "typeVersion": 3
    },
    {
      "id": "03eb468a-8ac2-473d-9fda-2d0435b5cd0a",
      "name": "GPT-4o Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
      "position": [
        1008,
        544
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "id",
          "value": "gpt-4o"
        },
        "options": {},
        "builtInTools": {}
      },
      "typeVersion": 1.3
    },
    {
      "id": "f480bfae-dbe1-417f-956e-3d7ed41836fb",
      "name": "Vector Store (Supabase)",
      "type": "@n8n/n8n-nodes-langchain.vectorStoreSupabase",
      "position": [
        1168,
        544
      ],
      "parameters": {
        "mode": "retrieve-as-tool",
        "options": {
          "queryName": "<__PLACEHOLDER_VALUE__SUPABASE_FUNCTION_NAME__>"
        },
        "tableName": {
          "__rl": true,
          "mode": "id",
          "value": "<__PLACEHOLDER_VALUE__SUPABASE_VECTOR_TABLE__>"
        },
        "toolDescription": "Retrieves relevant information from product manuals and documentation for [YOUR_DEVICE_TYPE] to help answer customer support questions"
      },
      "typeVersion": 1.3
    },
    {
      "id": "5a9988d5-77d8-46f3-8c99-49f64fee586c",
      "name": "OpenAI Embeddings",
      "type": "@n8n/n8n-nodes-langchain.embeddingsOpenAi",
      "position": [
        1168,
        752
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 1.2
    },
    {
      "id": "88d0d7f6-67fd-413e-b431-8e0ce97b596e",
      "name": "Build AI Prompt",
      "type": "n8n-nodes-base.code",
      "position": [
        800,
        288
      ],
      "parameters": {
        "jsCode": "const email = $('On Email Received').first().json;\nconst contact = $json; // From Supabase lookup\n\n// Extract contact details (Ensure these match your Supabase columns)\nconst senderName = contact.full_name || email.from || 'Unknown';\nconst senderEmail = email.from || '';\nconst hospitalName = contact.hospital_name || '';\nconst departmentName = contact.department_name || '';\nconst role = contact.role || '';\nconst emailBody = email.body || email.bodyPreview || '';\n\n// Build context with business rules\n// TODO: Customize these rules for your business case\nconst businessRules = `\nBUSINESS RULES:\n- Replies must be short (max 2-3 short paragraphs, optional bullets), friendly, professional.\n- No clinical or emergency medical advice; only equipment, pricing, logistics.\n- Only suggest accessories relevant to the sender's department.\n- Use consultative / solution-based selling, never hard sell.\n- If unsure about technical detail or price, say you will confirm and follow up instead of guessing.\n`;\n\nconst chatInput = `\nSender: ${senderName} (${senderEmail})\nHospital: ${hospitalName || 'Not available'}\nDepartment: ${departmentName || 'Not available'}\nRole: ${role || 'Not available'}\n\nEmail Subject: ${email.subject || 'No subject'}\nEmail Body:\n${emailBody}\n\n${businessRules}\n`;\n\nreturn {\n  json: {\n    chatInput: chatInput,\n    originalEmail: email\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "bba072e7-5ec6-470c-b0ca-962ef835b737",
      "name": "Fetch Contact Info",
      "type": "n8n-nodes-base.supabase",
      "position": [
        576,
        288
      ],
      "parameters": {
        "filters": {
          "conditions": [
            {
              "keyName": "email",
              "keyValue": "={{ $('On Email Received').first().json.from }}"
            }
          ]
        },
        "tableId": "<__PLACEHOLDER_VALUE__SUPABASE_CONTACTS_TABLE__>",
        "operation": "get"
      },
      "typeVersion": 1
    }
  ],
  "connections": {
    "GPT-4o Model": {
      "ai_languageModel": [
        [
          {
            "node": "AI Support Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Build AI Prompt": {
      "main": [
        [
          {
            "node": "AI Support Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI Support Agent": {
      "main": [
        [
          {
            "node": "Draft Outlook Reply",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Config Variables": {
      "main": [
        [
          {
            "node": "Fetch Contact Info",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "On Email Received": {
      "main": [
        [
          {
            "node": "Config Variables",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Embeddings": {
      "ai_embedding": [
        [
          {
            "node": "Vector Store (Supabase)",
            "type": "ai_embedding",
            "index": 0
          }
        ]
      ]
    },
    "Fetch Contact Info": {
      "main": [
        [
          {
            "node": "Build AI Prompt",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Draft Outlook Reply": {
      "main": [
        [
          {
            "node": "Log to Google Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Vector Store (Supabase)": {
      "ai_tool": [
        [
          {
            "node": "AI Support Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    }
  }
}