{
  "id": "6LQaqMZpjmf0H401",
  "name": "Bulk Email Validator - Google Sheets",
  "tags": [],
  "nodes": [
    {
      "id": "f0ea44c0-4d28-4c2b-b187-6c6494d12808",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        0,
        0
      ],
      "parameters": {
        "width": 480,
        "height": 736,
        "content": "## Bulk Email Validator - Google Sheets\n\n### How it works\n\n1. Triggers the workflow with manual, schedule, or webhook trigger.\n2. Reads email data from a Google Sheet.\n3. Parses and splits the email data into manageable batches.\n4. Verifies each batch of emails via an API call.\n5. Updates the Google Sheet with the verification results.\n\n### Setup steps\n\n- [ ] Set up Google Sheets API credentials.\n- [ ] Configure the [email verification](https://verify-email.app) API endpoint and key.\n- [ ] Set scheduled trigger time or URL for the webhook.\n\n### Customization\n\nYou can customize the verification API endpoint or adapt the script to handle different data formats."
      },
      "typeVersion": 1
    },
    {
      "id": "efad1fad-25b8-4398-bb6c-ca297fceebe8",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        560,
        0
      ],
      "parameters": {
        "color": 7,
        "height": 720,
        "content": "## Initial triggers\n\nHandles workflow initiation."
      },
      "typeVersion": 1
    },
    {
      "id": "baa72527-0330-4ce1-a2c3-bd52e4c7b10d",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1040,
        224
      ],
      "parameters": {
        "color": 7,
        "width": 496,
        "height": 272,
        "content": "## Fetch and parse data\n\nReads and prepares data from Google Sheets."
      },
      "typeVersion": 1
    },
    {
      "id": "cd012071-d3cd-47f7-bdee-83b43482d4ef",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1632,
        224
      ],
      "parameters": {
        "color": 7,
        "width": 352,
        "height": 512,
        "content": "## Batch processing control\n\nManages the processing of data batches."
      },
      "typeVersion": 1
    },
    {
      "id": "a8065045-627a-484b-82d4-2d468664852a",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2048,
        464
      ],
      "parameters": {
        "color": 7,
        "width": 432,
        "height": 272,
        "content": "## Verify and parse results\n\nHandles API call and parsing the returned data."
      },
      "typeVersion": 1
    },
    {
      "id": "4f403bfa-9310-49fc-9820-9e66ebdadfc5",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2544,
        176
      ],
      "parameters": {
        "color": 7,
        "height": 320,
        "content": "## Update results\n\nUpdates Google Sheets with email verification results."
      },
      "typeVersion": 1
    },
    {
      "id": "d16808b0-71ce-4932-8ed2-86d5a735e8fe",
      "name": "Every Monday at 8am",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        624,
        336
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "weeks",
              "triggerAtDay": [
                1
              ],
              "triggerAtHour": 8
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "5fe216aa-374e-46f8-a302-16cea58e1727",
      "name": "Read Emails from Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1088,
        336
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "1OlLamFW9r42Ag0V4cSdxLbOUcKkSosoXJI7VFUUyd14"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "0a1f3d74-a154-45fb-86ba-1b9ddf238b2c",
      "name": "Parse Email Data for Batches",
      "type": "n8n-nodes-base.code",
      "position": [
        1392,
        336
      ],
      "parameters": {
        "jsCode": "const allItems = $input.all();\nconst emailData = [];\n\nallItems.forEach((row, index) => {\n  const email = row.json?.Email?.trim?.();\n  if (!email) return;\n  \n  const status = row.json?.Status?.trim?.();\n  \n  if (status && status !== 'empty') {\n    return;\n  }\n  \n  const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n  if (!emailRegex.test(email)) return;\n  \n  emailData.push({\n    email: email.toLowerCase(),\n    row: row.json?.row_number || 0\n  });\n});\n\nif (emailData.length === 0) {\n  return [];\n}\n\nconst BATCH_SIZE = 100;\nconst batches = [];\n\nfor (let i = 0; i < emailData.length; i += BATCH_SIZE) {\n  const batch = emailData.slice(i, i + BATCH_SIZE);\n  batches.push({\n    emails: batch.map(e => e.email),\n    emailData: batch\n  });\n}\n\nreturn batches.map(batch => ({ json: batch }));"
      },
      "typeVersion": 2
    },
    {
      "id": "bb1f8064-4656-433c-9d06-bffb663f4172",
      "name": "Process in Batches of 10",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        1680,
        336
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "2229d4c6-192f-4dab-9e05-f572bb8c71b3",
      "name": "Post Email Batch to Verify API",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2096,
        576
      ],
      "parameters": {
        "url": "https://api.verify-email.app/v1/verify/batch",
        "method": "POST",
        "options": {
          "timeout": 60000
        },
        "jsonBody": "={{ JSON.stringify({ inputs: $json.emails }) }}\n",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "credentials": {
        "httpBearerAuth": {
          "name": "<your credential>"
        },
        "httpHeaderAuth": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "972d97e4-d3d0-4459-bcc1-87875bf6baa5",
      "name": "Parse Verification Results",
      "type": "n8n-nodes-base.code",
      "position": [
        2336,
        576
      ],
      "parameters": {
        "jsCode": "let apiResults = [];\n\ntry {\n  const response = $input.item.json;\n  apiResults = Array.isArray(response) ? response : response?.results || [];\n  \n  if (!Array.isArray(apiResults) || apiResults.length === 0) {\n    throw new Error('API returned empty response');\n  }\n} catch (e) {\n  throw new Error('API Error: ' + e.message);\n}\n\nconst currentBatch = $('Parse Email Data for Batches').item.json;\nconst emailData = currentBatch.emailData || [];\nconst emailToRow = {};\n\nemailData.forEach(e => {\n  emailToRow[e.email] = e;\n});\n\nconst results = apiResults.map(result => {\n  const originalData = emailToRow[result.email_address] || {};\n  const shouldBlock = result.block === true || result.valid === false;\n  \n  const reasons = [];\n  if (result.valid === false) reasons.push('Invalid');\n  if (result.block === true) reasons.push('Blacklisted');\n  if (result.disposable === true) reasons.push('Disposable');\n  \n  return {\n    Email: result.email_address,\n    Status: shouldBlock ? 'Block' : 'Valid',\n    Reason: reasons.join(' + ') || '-'\n  };\n});\n\nreturn results.map(r => ({ json: r }));"
      },
      "typeVersion": 2
    },
    {
      "id": "2974cdb5-6b14-4b77-8e00-3c452dd4d32c",
      "name": "Update Results in Sheets",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2592,
        336
      ],
      "parameters": {
        "columns": {
          "value": {
            "Email": "{{ $json.Email }}",
            "Reason": "{{ $json.Reason }}",
            "Status": "{{ $json.Status }}"
          },
          "schema": [
            {
              "id": "Email",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Email",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Status",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Reason",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "Reason",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "row_number",
              "type": "number",
              "display": true,
              "removed": true,
              "readOnly": true,
              "required": false,
              "displayName": "row_number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "autoMapInputData",
          "matchingColumns": [
            "Email"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "name",
          "value": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "id",
          "value": "1OlLamFW9r42Ag0V4cSdxLbOUcKkSosoXJI7VFUUyd14"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.5
    },
    {
      "id": "981aacac-6035-425a-924f-710e796a9324",
      "name": "Manual Trigger",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        608,
        128
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "55867ac0-eae7-4359-a427-1d82ef832c7b",
      "name": "Webhook Trigger",
      "type": "n8n-nodes-base.webhook",
      "disabled": true,
      "position": [
        608,
        544
      ],
      "parameters": {
        "path": "de5d1108-d424-4b89-9d85-41fae5885211",
        "options": {}
      },
      "typeVersion": 2.1
    },
    {
      "id": "8ab6c697-e471-4236-8148-156407893bf5",
      "name": "Check Emails Exist",
      "type": "n8n-nodes-base.if",
      "position": [
        1840,
        576
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "f41aa9f7-df89-4b6c-a36f-175876fb8be1",
              "operator": {
                "type": "number",
                "operation": "gt"
              },
              "leftValue": "={{ $json.emails.length }}",
              "rightValue": 0
            }
          ]
        }
      },
      "typeVersion": 2.3
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "versionId": "9c8d1f57-87d1-49be-908d-e05c764c716f",
  "connections": {
    "Webhook Trigger": {
      "main": [
        [
          {
            "node": "Read Emails from Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Emails Exist": {
      "main": [
        [
          {
            "node": "Post Email Batch to Verify API",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Every Monday at 8am": {
      "main": [
        [
          {
            "node": "Read Emails from Sheets",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read Emails from Sheets": {
      "main": [
        [
          {
            "node": "Parse Email Data for Batches",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Process in Batches of 10": {
      "main": [
        [
          {
            "node": "Update Results in Sheets",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Check Emails Exist",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Verification Results": {
      "main": [
        [
          {
            "node": "Process in Batches of 10",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Email Data for Batches": {
      "main": [
        [
          {
            "node": "Process in Batches of 10",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Post Email Batch to Verify API": {
      "main": [
        [
          {
            "node": "Parse Verification Results",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}