{
  "id": "foRLAgU7DfocKDuI",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Gmail \u2192 Zendesk: AI-Enriched Ticketing with Urgency Prioritization + Sheets Logging",
  "tags": [],
  "nodes": [
    {
      "id": "da98ac4e-67b4-4719-96dc-82dd69dc323e",
      "name": "Gmail Trigger",
      "type": "n8n-nodes-base.gmailTrigger",
      "position": [
        0,
        0
      ],
      "parameters": {
        "simple": false,
        "filters": {
          "labelIds": [
            "Label_7215267856143431312"
          ]
        },
        "options": {},
        "pollTimes": {
          "item": [
            {
              "mode": "everyMinute"
            }
          ]
        }
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "f8d28ce5-3c4c-4ba3-9534-aaf8aa10a01a",
      "name": "Create Zendesk Ticket",
      "type": "n8n-nodes-base.zendesk",
      "position": [
        848,
        0
      ],
      "parameters": {
        "description": "={{ $json.output.description }}",
        "additionalFields": {
          "tags": "={{ $json.output.priority }}",
          "subject": "={{ $json.output.subject }}"
        }
      },
      "credentials": {
        "zendeskApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "b4b1f7a4-0a31-4cd5-bfa2-78b5596e0c86",
      "name": "Format Sheet Data",
      "type": "n8n-nodes-base.code",
      "position": [
        1072,
        0
      ],
      "parameters": {
        "jsCode": "// Prepare data for Google Sheets logging\nconst inputData = $input.first().json;\nconst ticketData = $node[\"Create Zendesk Ticket\"].json;\n\n// Extract Zendesk subdomain from the API URL or construct the agent URL\nlet agentTicketUrl = '';\nif (ticketData.url) {\n  // Extract subdomain from API URL (e.g., https://softwarecompany-66332.zendesk.com/api/v2/tickets/123.json)\n  const urlMatch = ticketData.url.match(/https:\\/\\/(.*?)\\.zendesk\\.com/);\n  if (urlMatch) {\n    const subdomain = urlMatch[1];\n    agentTicketUrl = `https://${subdomain}.zendesk.com/agent/tickets/${ticketData.id}`;\n  } else {\n    // Fallback: construct from ticket ID (replace 'your-subdomain' with actual subdomain)\n    agentTicketUrl = `https://softwarecompany-66332.zendesk.com/agent/tickets/${ticketData.id}`;\n  }\n} else {\n  // Fallback if no URL is provided\n  agentTicketUrl = `https://softwarecompany-66332.zendesk.com/agent/tickets/${ticketData.id}`;\n}\n\nreturn {\n  ticket_id: ticketData.id,\n  ticket_url: agentTicketUrl,\n  api_url: ticketData.url, // Keep original API URL for reference\n  subject: ticketData.subject,\n  requester_name: inputData.requester_name,\n  requester_email: inputData.requester_email,\n  source_channel: inputData.source,\n  original_id: inputData.original_id,\n  priority: ticketData.priority,\n  status: ticketData.status,\n  created_timestamp: new Date().toISOString(),\n  zendesk_created_at: ticketData.created_at,\n  description_preview: inputData.description.substring(0, 100) + (inputData.description.length > 100 ? '...' : ''),\n  tags: ticketData.tags ? ticketData.tags.join(', ') : ''\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "80545193-9805-41f2-9a3d-a2740d943650",
      "name": "Normalize Gmail Data",
      "type": "n8n-nodes-base.code",
      "position": [
        224,
        0
      ],
      "parameters": {
        "jsCode": "// Normalize data from Gmail\nif ($input.first().json.source === undefined) {\n  const gmailData = $input.first().json;\n  \n  // Extract email and name from the 'from' object structure\n  let requesterEmail = '';\n  let requesterName = '';\n  \n  if (gmailData.from && gmailData.from.value && gmailData.from.value[0]) {\n    requesterEmail = gmailData.from.value[0].address || '';\n    requesterName = gmailData.from.value[0].name || gmailData.from.value[0].address || '';\n  }\n  \n  // Use plain text first, fallback to textAsHtml if text not available, avoid html\n  let description = '';\n  if (gmailData.text) {\n    description = gmailData.text;\n  } else if (gmailData.textAsHtml) {\n    // Strip HTML tags from textAsHtml to get plain text\n    description = gmailData.textAsHtml.replace(/<[^>]*>/g, '').replace(/&apos;/g, \"'\").replace(/&quot;/g, '\"').replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&amp;/g, '&');\n  } else {\n    description = 'No description provided';\n  }\n  \n  // Check if it's urgent based on subject or content\n  const isUrgent = (gmailData.subject && gmailData.subject.toLowerCase().includes('urgent')) || \n                   (description && description.toLowerCase().includes('urgent'));\n  \n  return {\n    source: 'gmail',\n    subject: gmailData.subject || 'No Subject',\n    description: description,\n    requester_email: requesterEmail,\n    requester_name: requesterName,\n    priority: isUrgent ? 'urgent' : 'normal',\n    timestamp: new Date().toISOString(),\n    original_id: gmailData.id,\n    raw_data: gmailData\n  };\n}\n\nreturn $input.first().json;"
      },
      "typeVersion": 2
    },
    {
      "id": "863bd681-6a7d-464c-a3d4-29df6459f531",
      "name": "Azure OpenAI Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatAzureOpenAi",
      "position": [
        480,
        224
      ],
      "parameters": {
        "model": "gpt-4o-mini",
        "options": {}
      },
      "credentials": {
        "azureOpenAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "d5ff38ae-3b60-4517-9a3f-a725787d5d1e",
      "name": "Structured Output Parser",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        608,
        224
      ],
      "parameters": {
        "jsonSchemaExample": "{\n\t\"subject\": \" \",\n\t\"description\": \" \",\n    \"priority\": \"normal\"\n}"
      },
      "typeVersion": 1.3
    },
    {
      "id": "cb6a9454-90e1-47da-8a72-a4ccc2892d63",
      "name": "Log to Google Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1296,
        0
      ],
      "parameters": {
        "columns": {
          "value": {
            "Tags": "={{ $json.tags }}",
            "Status": "={{ $json.status }}",
            "Subject": "={{ $json.subject }}",
            "Priority": "={{ $json.priority }}",
            "Ticket ID": "={{ $json.ticket_id }}",
            "Ticket URL": "={{ $json.ticket_url }}",
            "Created Timestamp": "={{ $json.created_timestamp }}",
            "Zendesk Created At": "={{ $json.zendesk_created_at }}",
            "Description Preview": "={{ $json.description_preview }}"
          },
          "schema": [
            {
              "id": "Ticket ID",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Ticket ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Ticket URL",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Ticket URL",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Subject",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Subject",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Requester Name",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "Requester Name",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Requester Email",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "Requester Email",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Source Channel",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "Source Channel",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Original ID",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "Original ID",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Priority",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Priority",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Status",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Created Timestamp",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Created Timestamp",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Zendesk Created At",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Zendesk Created At",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Description Preview",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Description Preview",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Tags",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "Tags",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "Ticket ID"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "appendOrUpdate",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1pz1aP0OIULFoEJCI6VWged3jq1W7870btV2QOC4vn1o/edit#gid=0",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1pz1aP0OIULFoEJCI6VWged3jq1W7870btV2QOC4vn1o",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1pz1aP0OIULFoEJCI6VWged3jq1W7870btV2QOC4vn1o/edit?usp=drivesdk",
          "cachedResultName": "zendesk tickets"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4
    },
    {
      "id": "90b394e5-2c06-4465-b297-d2dea19809b2",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -352,
        -32
      ],
      "parameters": {
        "height": 192,
        "content": "## Gmail Trigger\nWatches a specified Gmail inbox/label for new messages. Captures sender, subject, timestamp, thread ID, and raw body/HTML for downstream processing and urgency assessment."
      },
      "typeVersion": 1
    },
    {
      "id": "78578cb1-e1aa-4ed9-bc49-378ab0ae414c",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        144,
        -288
      ],
      "parameters": {
        "height": 240,
        "content": "## Normalize Gmail Data\nCleans and standardizes the incoming email: strips signatures/quotes, extracts plain text, detects language, and maps fields (from, to, cc, subject, body, attachments) into a consistent schema for AI parsing and prioritization."
      },
      "typeVersion": 1
    },
    {
      "id": "cf4a6d75-f9f9-430a-ad4c-b138aecdcdd4",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        496,
        384
      ],
      "parameters": {
        "height": 256,
        "content": "## Chat Model\nUses Azure OpenAI to analyze the normalized email and produce structured insights: issue summary, category, requested action, and an urgency score/class (Critical/High/Medium/Low) based on keywords, sender context, timestamps, and SLA hints."
      },
      "typeVersion": 1
    },
    {
      "id": "7ace00b5-95a6-47b1-bc15-0cc406997363",
      "name": "AI Agent for Task Prioritization",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        448,
        0
      ],
      "parameters": {
        "text": "=You are an assistant that converts incoming emails into task metadata.\n\nInputs:\n- email_subject: string\n- email_description: string (can include bullet points, deadlines, owners)\n\nGoals:\nFrom the inputs, produce:\n1) task_subject: A clear, action-oriented subject (\u2264120 chars), preserving critical keywords from email_subject.\n2) task_description: A concise, well-structured description (3\u20138 bullet points). Include scope, deliverables, due date/time if present, owners/reviewers, and any channels/tools mentioned. Preserve key details without adding new facts.\n3) task_priority: One of [\"urgent\",\"normal\"] using these rules:\n   - \"urgent\" if the email includes explicit urgency or near-term deadlines (e.g., \"today\", \"tomorrow\", \"<=48h\", \"ASAP\", \"urgent\", \"immediately\") or high-impact incidents/outages.\n   - Otherwise \"normal\".\n\nStyle:\n- Use crisp, professional language.\n- Normalize whitespace and fix obvious typos.\n- Do not invent data.\n\n\nNow process:\nemail_subject = \"{{ $json.subject }}\"\nemail_description = \"{{ $json.description }}\"",
        "options": {},
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 2.1
    },
    {
      "id": "889ec0b1-e694-41ff-add2-e24046960316",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        768,
        -304
      ],
      "parameters": {
        "height": 256,
        "content": "## Create Zendesk Ticket\nCreates a Zendesk ticket using the structured data: requester, subject, description, tags, and priority set from urgency classification (Critical \u2192 urgent, High \u2192 high, etc.). Adds category and SLA hints to custom fields."
      },
      "typeVersion": 1
    },
    {
      "id": "073e6228-e9c2-433f-a5b4-5519c149ce3e",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        992,
        176
      ],
      "parameters": {
        "height": 192,
        "content": "## Format Sheet Data\nPrepares a clean row for Google Sheets: received_at, sender, subject, summary, category, priority_by_urgency, zendesk_ticket_id, status, and processing time. Normalizes values for consistent reporting."
      },
      "typeVersion": 1
    },
    {
      "id": "c836b9fb-2153-41ae-9517-29c24e166792",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1248,
        -288
      ],
      "parameters": {
        "height": 208,
        "content": "## Log to Google Sheets\nAppends or updates the tracking sheet with each processed email and its urgency priority. Enables auditing, SLA monitoring, and trend analysis across tickets."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "d011873d-949e-46cc-a604-f7a866270079",
  "connections": {
    "Gmail Trigger": {
      "main": [
        [
          {
            "node": "Normalize Gmail Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Sheet Data": {
      "main": [
        [
          {
            "node": "Log to Google Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize Gmail Data": {
      "main": [
        [
          {
            "node": "AI Agent for Task Prioritization",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create Zendesk Ticket": {
      "main": [
        [
          {
            "node": "Format Sheet Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Azure OpenAI Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent for Task Prioritization",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Structured Output Parser": {
      "ai_outputParser": [
        [
          {
            "node": "AI Agent for Task Prioritization",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "AI Agent for Task Prioritization": {
      "main": [
        [
          {
            "node": "Create Zendesk Ticket",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}