{
  "id": "KZON3Mzef2dj29N2",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Gmail Support Emails to Zendesk Tickets with Spam & Duplicate Prevention",
  "tags": [],
  "nodes": [
    {
      "id": "3ae5ec4d-60ad-42a0-8479-2b3d20c191a9",
      "name": "New Support Email Trigger",
      "type": "n8n-nodes-base.gmailTrigger",
      "position": [
        -160,
        16
      ],
      "parameters": {
        "filters": {},
        "pollTimes": {
          "item": [
            {
              "mode": "everyMinute"
            }
          ]
        }
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "bec74235-dabc-44a0-91e0-bc86861ff2a5",
      "name": "Spam Detection & Filtering",
      "type": "n8n-nodes-base.code",
      "position": [
        304,
        16
      ],
      "parameters": {
        "jsCode": "const item = $json;\n\nconst subject = (item.subject || '').toLowerCase();\nconst body = (item.description || '').toLowerCase();\nconst email = (item.customer_email || '').toLowerCase();\n\n// Common spam keywords\nconst spamKeywords = [\n  'win money',\n  'free gift',\n  'click here',\n  'urgent action',\n  'lottery',\n  'bitcoin',\n  'crypto',\n  'investment opportunity'\n];\n\n// Suspicious email domains\nconst spamDomains = [\n  'tempmail',\n  '10minutemail',\n  'mailinator',\n  'guerrillamail'\n];\n\n// Keyword match\nconst keywordSpam = spamKeywords.some(k =>\n  subject.includes(k) || body.includes(k)\n);\n\n// Domain match\nconst domainSpam = spamDomains.some(d =>\n  email.includes(d)\n);\n\n// Final spam decision\nconst isSpam = keywordSpam || domainSpam;\n\n// If spam \u2192 stop workflow\nif (isSpam) {\n  return [];\n}\n\n// Not spam \u2192 continue\nreturn [{ json: item }];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "3c20ee8a-b80c-44d6-84fa-fed064265ec5",
      "name": "Extract & Normalize Email Data",
      "type": "n8n-nodes-base.set",
      "position": [
        736,
        16
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "b17f683e-18b3-4739-90d7-678545009274",
              "name": "=customer_name",
              "type": "string",
              "value": "={{$json[\"From\"].split(\" <\")[0]}}"
            },
            {
              "id": "2bc4671b-2ab3-4248-8cc2-768869bbf868",
              "name": "customer_email",
              "type": "string",
              "value": "={{$json[\"From\"].match(/<(.+)>/)[1]}}"
            },
            {
              "id": "20bfdc42-25c2-4ac0-b342-5fca279e33a9",
              "name": "subject",
              "type": "string",
              "value": "={{$json[\"Subject\"]}}"
            },
            {
              "id": "68ff09ea-01ee-4891-9d77-8c30d8ec6848",
              "name": "description",
              "type": "string",
              "value": "={{$json[\"snippet\"]}}"
            },
            {
              "id": "90d82dab-45dd-4e82-898b-a6cba4d0fc11",
              "name": "=thread_id",
              "type": "string",
              "value": "={{ $json.threadId }}"
            },
            {
              "id": "c8274cde-d223-421d-97b0-03d09a040a11",
              "name": "received_at",
              "type": "string",
              "value": "={{$json[\"internalDate\"]}}"
            },
            {
              "id": "68bfb284-97be-4236-bed4-095e42ddd2da",
              "name": "tags",
              "type": "string",
              "value": "={{$json[\"snippet\"].toLowerCase().includes(\"refund\") ? [\"refund\"] : []}}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "fb6264e5-fc17-488a-8b5c-a52cc38ddccf",
      "name": "Auto-Tag Ticket Based on Email Content",
      "type": "n8n-nodes-base.code",
      "position": [
        1008,
        -96
      ],
      "parameters": {
        "jsCode": "// Get email body from previous node\nconst emailBody = $json[\"description\"].toLowerCase();\n\n// Define keywords and corresponding tags\nconst keywordTags = {\n  \"refund\": \"refund\",\n  \"damaged\": \"damaged\",\n  \"late delivery\": \"late_delivery\"\n};\n\n// Initialize tags array\nlet tags = [];\n\n// Loop through keywords and add tags if found\nfor (const keyword in keywordTags) {\n  if (emailBody.includes(keyword)) {\n    tags.push(keywordTags[keyword]);\n  }\n}\n\n// Return updated data\nreturn [\n  {\n    json: {\n      ...$json,\n      tags\n    }\n  }\n];\n"
      },
      "typeVersion": 2
    },
    {
      "id": "f7c03701-9a47-44d1-a1d1-4bb07bee340a",
      "name": "Zendesk \u2013 Fetch Existing Tickets",
      "type": "n8n-nodes-base.zendesk",
      "position": [
        1008,
        80
      ],
      "parameters": {
        "options": {},
        "operation": "getAll",
        "authentication": "oAuth2"
      },
      "credentials": {
        "zendeskOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "6481eb72-b926-4030-842a-a428d05e78f8",
      "name": "Merge Email With Existing Tickets",
      "type": "n8n-nodes-base.merge",
      "position": [
        1456,
        16
      ],
      "parameters": {},
      "typeVersion": 3.2
    },
    {
      "id": "aa789d1a-232d-458f-b75b-b3c9641843ce",
      "name": "Detect Duplicate Ticket by Subject",
      "type": "n8n-nodes-base.code",
      "position": [
        1648,
        16
      ],
      "parameters": {
        "jsCode": "// Get all merged items\nconst items = $input.all();\n\n// First item is always the email\nconst email = items[0].json;\n\n// Remaining items are Zendesk tickets\nconst tickets = items.slice(1).map(i => i.json);\n\n// Safety check\nif (!email || !email.subject) {\n  throw new Error('Missing email subject');\n}\n\n// Normalize function\nconst normalize = (str) =>\n  str.trim().toLowerCase();\n\n// Check if subject already exists in Zendesk\nconst isDuplicate = tickets.some(ticket =>\n  ticket.subject &&\n  normalize(ticket.subject) === normalize(email.subject)\n);\n\n// If duplicate \u2192 stop workflow\nif (isDuplicate) {\n  return [];\n}\n\n// If NOT duplicate \u2192 allow ticket creation\nreturn [\n  {\n    json: email\n  }\n];\n"
      },
      "typeVersion": 2,
      "alwaysOutputData": true
    },
    {
      "id": "43b0a0d4-3dfa-4e87-9072-7476c677a857",
      "name": "Is This a New Ticket?",
      "type": "n8n-nodes-base.if",
      "position": [
        1840,
        16
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 2,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "ec29a493-1e47-4dd1-87a2-846d9506debb",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{$json.isEmpty()}}",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "28ae617a-65fa-4418-bf8d-7bc8b0b21f26",
      "name": "Create Zendesk Support Ticket",
      "type": "n8n-nodes-base.zendesk",
      "position": [
        2256,
        32
      ],
      "parameters": {
        "description": "={{ $json.description }}",
        "authentication": "oAuth2",
        "jsonParameters": true,
        "additionalFieldsJson": "={\n  \"subject\": \"{{ $json.subject }}\",\n  \"comment\": {\n    \"body\": \"{{ $json.description }}\"\n  },\n  \"requester\": {\n    \"name\": \"{{ $json.customer_name }}\",\n    \"email\": \"{{ $json.customer_email }}\"\n  },\n  \"tags\": \"{{ $json.tags }}\",\n  \"priority\": \"high\",\n  \"status\": \"open\",\n  \"external_id\": \"{{ $json.thread_id }}\"\n}\n"
      },
      "credentials": {
        "zendeskOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1
    },
    {
      "id": "e1aeb752-3e5a-4551-bf2e-c58041665ca3",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -320,
        -144
      ],
      "parameters": {
        "color": 7,
        "width": 432,
        "height": 400,
        "content": "## Incoming Support Email Trigger\nThis section listens for new customer messages sent to the support inbox. Whenever a new email arrives, the workflow automatically starts, ensuring no customer request is missed and every support inquiry enters the automation flow in real time."
      },
      "typeVersion": 1
    },
    {
      "id": "dce28e0f-3cd2-4ce5-9ab4-99123d8a0a81",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        160,
        -144
      ],
      "parameters": {
        "color": 7,
        "width": 448,
        "height": 400,
        "content": "## Spam Detection & Early Filtering\nThis section checks the email subject, message content and sender domain to detect spam. Any suspicious or unwanted emails are stopped immediately, ensuring only genuine customer queries are processed and sent to Zendesk."
      },
      "typeVersion": 1
    },
    {
      "id": "140ce5ba-548e-4445-a947-caa3f90c51cc",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        656,
        -304
      ],
      "parameters": {
        "color": 7,
        "width": 576,
        "height": 560,
        "content": "## Prepare Email Data & Check Existing Tickets\nThis section cleans and structures incoming email data by extracting customer details, message content and tags. It then retrieves existing Zendesk tickets to provide context, enabling accurate comparison and helping the workflow determine whether the incoming request is new or already recorded."
      },
      "typeVersion": 1
    },
    {
      "id": "72c9bac5-55d5-4a3d-ae74-fbadc329a549",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1344,
        -144
      ],
      "parameters": {
        "color": 7,
        "width": 720,
        "height": 384,
        "content": "## Duplicate Detection & Validation\nIn this section, the incoming email is compared with existing Zendesk tickets. By checking normalized subjects and identifiers, the workflow determines whether the email represents a new issue or a duplicate, ensuring only valid new tickets move forward."
      },
      "typeVersion": 1
    },
    {
      "id": "83d7aeb4-324c-4fef-afd8-89a0ba3e4cd2",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2128,
        -144
      ],
      "parameters": {
        "color": 7,
        "width": 432,
        "height": 384,
        "content": "## Zendesk Ticket Creation\nThis final section creates a new support ticket in Zendesk using the cleaned and validated data. The ticket includes customer details, message content, priority, tags and external identifiers, ensuring the support team receives a complete and actionable request."
      },
      "typeVersion": 1
    },
    {
      "id": "768133f1-3878-410d-afd9-72b310c06472",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1056,
        -704
      ],
      "parameters": {
        "width": 624,
        "height": 720,
        "content": "## How It Works\nThis workflow automatically converts customer support emails into structured Zendesk tickets while keeping the support system clean and organized. It starts when a new email arrives in the support inbox. The workflow first checks whether the email looks like spam and stops it early if it does.\n\nFor valid emails, the workflow extracts important details such as the customer\u2019s name, email address, subject, message content and email thread ID. Based on the message content, it also adds helpful tags like \u201crefund\u201d or \u201cdamaged\u201d to provide quick context for the support team.\n\nBefore creating a new ticket, the workflow checks existing Zendesk tickets to see if a similar request already exists. If a duplicate is detected, the workflow stops to avoid creating multiple tickets for the same issue. Only genuine, new support requests move forward and get created as Zendesk tickets with all required information.\n\n## Workflow Setup Steps\n\nAdd an Email or Gmail Trigger to listen for new messages in the support inbox.\n\nAdd a Spam Detection node to filter out unwanted or suspicious emails early.\n\nUse a Set node to extract and organize important email details like customer name, email, subject, message body and thread ID.\n\nAdd a Tagging node to automatically apply relevant tags based on the email content.\n\nFetch existing tickets from Zendesk to check for duplicates.\n\nMerge the email data with existing tickets and run a Duplicate Check.\n\nIf no duplicate is found, create a new ticket using the Zendesk Create Ticket node."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "98efe619-8474-4cb6-93e6-c832172d73e4",
  "connections": {
    "Is This a New Ticket?": {
      "main": [
        [],
        [
          {
            "node": "Create Zendesk Support Ticket",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "New Support Email Trigger": {
      "main": [
        [
          {
            "node": "Spam Detection & Filtering",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Spam Detection & Filtering": {
      "main": [
        [
          {
            "node": "Extract & Normalize Email Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract & Normalize Email Data": {
      "main": [
        [
          {
            "node": "Auto-Tag Ticket Based on Email Content",
            "type": "main",
            "index": 0
          },
          {
            "node": "Zendesk \u2013 Fetch Existing Tickets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge Email With Existing Tickets": {
      "main": [
        [
          {
            "node": "Detect Duplicate Ticket by Subject",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Detect Duplicate Ticket by Subject": {
      "main": [
        [
          {
            "node": "Is This a New Ticket?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Zendesk \u2013 Fetch Existing Tickets": {
      "main": [
        [
          {
            "node": "Merge Email With Existing Tickets",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Auto-Tag Ticket Based on Email Content": {
      "main": [
        [
          {
            "node": "Merge Email With Existing Tickets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}