AutomationFlowsEmail & Gmail › Validate Bulk Email Addresses in Google Sheets with Verify Email

Validate Bulk Email Addresses in Google Sheets with Verify Email

ByAlex @crispy on n8n.io

Automatically validate email addresses in Google Sheets using Verify Email

Cron / scheduled trigger★★★★☆ complexity16 nodesGoogle SheetsHTTP Request
Email & Gmail Trigger: Cron / scheduled Nodes: 16 Complexity: ★★★★☆ Added:

This workflow corresponds to n8n.io template #15344 — we link there as the canonical source.

This workflow follows the Google Sheets → HTTP Request recipe pattern — see all workflows that pair these two integrations.

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →

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

Credentials you'll need

Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

Automatically validate email addresses in Google Sheets using Verify Email

Source: https://n8n.io/workflows/15344/ — original creator credit. Request a take-down →

More Email & Gmail workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Email & Gmail

YOUR_ID 4. Uses gmail, googleDrive, googleSheets, httpRequest. Scheduled trigger; 53 nodes.

Gmail, Google Drive, Google Sheets +1
Email & Gmail

Looking for a way to track GitHub bounty issues automatically and get notified in real time? This GitHub Bounty Tracker workflow monitors repositories for issues labeled 💎 Bounty, logs them in Google

Google Sheets, HTTP Request, WhatsApp +1
Email & Gmail

This workflow automatically sends a beautifully designed HTML newsletter every Sunday at 8 AM, featuring products currently on sale from your Algolia-powered e-commerce store.

Google Sheets, HTTP Request, Gmail
Email & Gmail

This n8n template demonstrates how to build a Auto Lead Gen & Outreach System for Local Businesses specifically designed to help businesses that don’t have a website yet.

Google Sheets, HTTP Request, Google Drive +1
Email & Gmail

I created this workflow with care for marketing professionals and agencies who manage multiple Meta Ads (Facebook) accounts and want to track ad account balances automatically — no more logging in eve

HTTP Request, Google Sheets, Gmail