Gmail email verification with BillionVerify
Gmail is Google's widely used email platform, relied on by individuals and businesses to send, receive, and organize messages. When you use Gmail in automated workflows — importing contacts, sending outreach, or triggering follow-ups — the quality of the addresses you reach determines whether those messages land in inboxes or bounce back.
Why verify before the send
Unverified addresses routed through Gmail-based automations inflate bounce rates, erode your Google Workspace sender reputation, and risk getting your domain flagged by spam filters. BillionVerify checks each address for validity, disposable patterns, role accounts, and catch-all status so every message you send from Gmail reaches a real, active recipient.
Ready-to-use n8n workflow
Import this workflow into n8n — it verifies every address with BillionVerify before Gmail sends, so only deliverable contacts are emailed. Install the BillionVerify community node first, then add your API key. Adapted from this n8n template
{
"name": "Extract web page data from Gmail links and save to Google Sheets + BillionVerify",
"nodes": [
{
"id": "996ac1ec-c471-4734-a82c-c44c16ce74ad",
"name": "When clicking ‘Test workflow’",
"type": "n8n-nodes-base.manualTrigger",
"position": [
-1728,
-400
],
"parameters": {},
"typeVersion": 1
},
{
"id": "8473c056-35d1-4e47-96dd-e0cb30e14ad1",
"name": "Search Emails",
"type": "n8n-nodes-base.gmail",
"position": [
-1504,
-400
],
"webhookId": "55c11b0e-7461-43de-b9d3-a3904f3dd525",
"parameters": {
"simple": false,
"filters": {
"sender": "user@example.com",
"receivedAfter": "2025-09-30T00:00:00",
"receivedBefore": "2025-09-22T00:00:00"
},
"options": {},
"operation": "getAll",
"returnAll": true
},
"credentials": {
"gmailOAuth2": {
"id": "credential-id",
"name": "gmailOAuth2 Credential"
}
},
"typeVersion": 2.1
},
{
"id": "2c6c6140-160d-4198-a0cc-3fa17530859e",
"name": "search for an element in the email body",
"type": "n8n-nodes-base.html",
"position": [
-1280,
-400
],
"parameters": {
"options": {},
"operation": "extractHtmlContent",
"dataPropertyName": "html",
"extractionValues": {
"values": [
{
"key": "dados",
"attribute": "href",
"cssSelector": "=a[style*=\"color: #ffffff\"]",
"returnValue": "attribute"
}
]
}
},
"typeVersion": 1.2
},
{
"id": "7e6693f3-0607-49a3-9725-d844a8b45319",
"name": "open the link",
"type": "n8n-nodes-base.httpRequest",
"onError": "continueErrorOutput",
"position": [
-1072,
-400
],
"parameters": {
"url": "={{ $json.dados }}",
"options": {}
},
"retryOnFail": false,
"typeVersion": 4.2,
"alwaysOutputData": false
},
{
"id": "4a04204c-e8dc-4865-963a-000378aa1024",
"name": "capture data",
"type": "n8n-nodes-base.html",
"position": [
-832,
-416
],
"parameters": {
"options": {},
"operation": "extractHtmlContent",
"extractionValues": {
"values": [
{
"key": "dtnasc",
"cssSelector": "#lblMemberDateOfBirth"
},
{
"key": "id",
"cssSelector": "#txtCase"
},
{
"key": "data_solicitacao",
"cssSelector": "#lblCaseOpenOn"
},
{
"key": "Local_pt01",
"cssSelector": "#lblMemberFullAddress"
},
{
"key": "Local_pt02",
"cssSelector": "#lblLocationHotelName"
},
{
"key": "Nome",
"cssSelector": "#lblMemberFirstName"
},
{
"key": "sobrenome",
"cssSelector": "#lblMemberLastName"
},
{
"key": "Queixa",
"cssSelector": "#lblCaseReportedIssue"
},
{
"key": "Link",
"cssSelector": "=",
"returnValue": "value"
}
]
}
},
"typeVersion": 1.2
},
{
"id": "a3d87c4d-1c96-461c-bc45-42e4a3c7469c",
"name": "processes information",
"type": "n8n-nodes-base.code",
"position": [
-608,
-416
],
"parameters": {
"jsCode": "// Função para converter string \"DD/MM/YYYY HH:MM\" para objeto Date\nfunction parseDateOnly(dateTimeStr) {\n if (!dateTimeStr) return null;\n const parts = dateTimeStr.split(' ')[0].split('/'); // pega apenas DD/MM/YYYY\n if (parts.length !== 3) return null;\n const day = parseInt(parts[0], 10);\n const month = parseInt(parts[1], 10) - 1; // meses em JS vão de 0 a 11\n const year = parseInt(parts[2], 10);\n return new Date(year, month, day);\n}\n\n// Função para extrair apenas o número do ID, removendo prefixos como \"Caso ID :\" ou \"Case ID :\"\nfunction extractCaseId(idStr) {\n if (!idStr) return null;\n return idStr.replace(/(Caso|Case)\\s*ID\\s*:\\s*/i, '').trim();\n}\n\n// Recupera todos os e-mails e links correspondentes\nconst emailItems = $('Search Emails').all();\nconst linkItems = $('search for an element in the email body').all();\n\n// Percorre todos os itens de entrada\nconst results = [];\nconst inputItems = $input.all();\n\nfor (let i = 0; i < inputItems.length; i++) {\n const item = inputItems[i];\n const birthDateStr = item.json.dtnasc;\n const requestDateTimeStr = item.json.data_solicitacao;\n const rawId = item.json.id;\n\n // Tratamento do ID\n const caseId = extractCaseId(rawId);\n\n // Captura o subject e o link correspondentes (mesmo índice)\n const emailSubject = emailItems[i]?.json?.headers?.subject || null;\n const emailLink = linkItems[i]?.json?.dados || null;\n\n // Determina o tipo de atendimento com base no subject\n let attendanceType = \"PRESENCIAL\";\n if (emailSubject && emailSubject.toLowerCase().includes(\"tele-medicine\")) {\n attendanceType = \"TELEMEDICINA\";\n }\n\n // Se faltar algum dado essencial, apenas devolve o item como está\n if (!birthDateStr || !requestDateTimeStr) {\n results.push({\n json: {\n ...item.json,\n caseId: caseId || null,\n emailSubject: emailSubject,\n attendanceType: attendanceType,\n link: emailLink\n }\n });\n continue;\n }\n\n const birthDate = parseDateOnly(birthDateStr);\n\n // Separar data e horário\n const [datePart, timePart] = requestDateTimeStr.split(' '); // \"DD/MM/YYYY\" e \"HH:MM\"\n const requestDate = parseDateOnly(datePart);\n\n if (!birthDate || !requestDate) {\n results.push({\n json: {\n ...item.json,\n caseId: caseId || null,\n emailSubject: emailSubject,\n attendanceType: attendanceType,\n link: emailLink\n }\n });\n continue;\n }\n\n // Calcula a idade\n let age = requestDate.getFullYear() - birthDate.getFullYear();\n const m = requestDate.getMonth() - birthDate.getMonth();\n if (m < 0 || (m === 0 && requestDate.getDate() < birthDate.getDate())) {\n age--;\n }\n\n // Retorna o item completo com todos os campos tratados\n results.push({\n json: {\n ...item.json,\n age: age,\n requestDate: datePart, // apenas a data\n requestTime: timePart, // apenas o horário\n caseId: caseId, // número do caso limpo\n emailSubject: emailSubject, // texto do subject do e-mail\n attendanceType: attendanceType, // \"TELEMEDICINA\" ou \"PRESENCIAL\"\n link: emailLink // link correspondente ao e-mail\n }\n });\n}\n\nreturn results;\n"
},
"typeVersion": 2
},
{
"id": "ac95be81-23fa-4833-9bbf-46a68d172a2f",
"name": "set variables",
"type": "n8n-nodes-base.set",
"position": [
-384,
-416
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "bcf5bbaa-2930-4c59-93c3-add1b31fdb7c",
"name": "id",
"type": "string",
"value": "={{ $json.caseId }}"
},
{
"id": "c46a4f49-c77f-4239-83f2-1a1334bf31ae",
"name": "Nome_Paciente",
"type": "string",
"value": "={{ $json.Nome }} {{ $json.sobrenome }}"
},
{
"id": "a2b523a0-6d65-442f-a23a-5e2ec3e8f17f",
"name": "Dt_solicitacao",
"type": "string",
"value": "={{ $json.requestDate }}"
},
{
"id": "7b421b6a-99fe-479a-ac7d-c580c02f6ee0",
"name": "Queixa",
"type": "string",
"value": "={{ $json.Queixa }}"
},
{
"id": "11941808-a53b-4d12-aaef-910120a5b512",
"name": "Idade",
"type": "string",
"value": "={{ $json.age }}"
},
{
"id": "9a0ff300-33ec-4dc6-831f-e21ad8148b84",
"name": "Local",
"type": "string",
"value": "={{ $json.Local_pt01 }} {{ $json.Local_pt02 }}"
},
{
"id": "0133b215-4db9-47ea-a2b8-ef80a4f052fa",
"name": "horario",
"type": "string",
"value": "={{ $json.requestTime }}"
},
{
"id": "a42de334-56c3-4180-bc7c-d926ebd4c2b2",
"name": "Link",
"type": "string",
"value": "={{ $json.link }}"
},
{
"id": "85b87a31-662f-4ef4-9b73-9211b0bd9511",
"name": "Tipo atendimento",
"type": "string",
"value": "={{ $json.attendanceType }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "907f9531-8fdd-4bce-9a8a-b03e7edsdsdsd202180",
"name": "Save data in spreadsheet",
"type": "n8n-nodes-base.googleSheets",
"position": [
-144,
-416
],
"parameters": {
"columns": {
"value": {
"DATA": "={{ $json.Dt_solicitacao }}",
"LINK": "={{ $json.Link }}",
"NOME": "={{ $json.Nome_Paciente }}",
" CASO": "={{ $json.id }}",
"IDADE": "={{ $json.Idade }}",
"LOCAL": "={{ $json.Local }}",
"QUEIXA": "={{ $json.Queixa }}",
"HORÁRIO": "={{ $json.horario }}",
"TIPO CONSULTA ": "={{ $json['Tipo atendimento'] }}"
},
"schema": [
{
"id": "HORÁRIO",
"type": "string",
"display": true,
"required": false,
"displayName": "HORÁRIO",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "DATA",
"type": "string",
"display": true,
"required": false,
"displayName": "DATA",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "EMPRESA",
"type": "string",
"display": true,
"required": false,
"displayName": "EMPRESA",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "TIPO CONSULTA ",
"type": "string",
"display": true,
"required": false,
"displayName": "TIPO CONSULTA ",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "LOCAL",
"type": "string",
"display": true,
"required": false,
"displayName": "LOCAL",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "NOME",
"type": "string",
"display": true,
"required": false,
"displayName": "NOME",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": " CASO",
"type": "string",
"display": true,
"required": false,
"displayName": " CASO",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "IDADE",
"type": "string",
"display": true,
"required": false,
"displayName": "IDADE",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "QUEIXA",
"type": "string",
"display": true,
"required": false,
"displayName": "QUEIXA",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "LINK",
"type": "string",
"display": true,
"required": false,
"displayName": "LINK",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "DIAGNOSTICO",
"type": "string",
"display": true,
"required": false,
"displayName": "DIAGNOSTICO",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "MEDICAÇÃO PRESCRITA",
"type": "string",
"display": true,
"required": false,
"displayName": "MEDICAÇÃO PRESCRITA",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "INJETAVEIS /PROCEDIMENTOS",
"type": "string",
"display": true,
"required": false,
"displayName": "INJETAVEIS /PROCEDIMENTOS",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "list",
"value": 311390915,
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1bbcFz1111wO77RBr0t8hYaAEuzEsr24MJrFWuIPzoC-XMjx8/edit#gid=311390915",
"cachedResultName": "Outubro-2025"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1bbcFzO77RBr0t8hYaAEuzEsr24MJrFWuIPzoC-XMjx8",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1bbcFz111O77RBr0t8hYaAEuzEsr24MJrFWuIPzoC-XMjx8/edit?usp=drivesdk",
"cachedResultName": "NOREPLY"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"id": "credential-id",
"name": "googleSheetsOAuth2Api Credential"
}
},
"typeVersion": 4.7
},
{
"id": "9fedd068-0a9b-44a1-bde1-de312dfc6ced",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1568,
-496
],
"parameters": {
"width": 208,
"height": 272,
"content": "**earch for emails** received from a sender within a specific time period."
},
"typeVersion": 1
},
{
"id": "584ddb97-097b-452c-a632-a534537965d0",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1344,
-496
],
"parameters": {
"color": 4,
"width": 208,
"height": 272,
"content": "**Search for a specific css element** in the email code"
},
"typeVersion": 1
},
{
"id": "f1d3e50c-a187-421f-95a1-009f1f5c8f49",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1120,
-496
],
"parameters": {
"color": 3,
"width": 208,
"height": 272,
"content": "**access the link** found in the HTML body of the email"
},
"typeVersion": 1
},
{
"id": "c434b579-5fb5-4813-9944-7af5f54101e6",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-896,
-496
],
"parameters": {
"color": 4,
"width": 208,
"height": 272,
"content": "**Search for a specific css element** in the email code"
},
"typeVersion": 1
},
{
"id": "69282cbc-b64e-4923-b67d-f279cca4e509",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
-672,
-496
],
"parameters": {
"color": 5,
"width": 208,
"height": 272,
"content": "js code to process the extracted data, **customize as you wish**"
},
"typeVersion": 1
},
{
"id": "df2ead67-1e19-4cec-a79c-47259d756545",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
-448,
-496
],
"parameters": {
"color": 5,
"width": 208,
"height": 272,
"content": "set the desired variables to save"
},
"typeVersion": 1
},
{
"id": "2d494ae1-6ab6-473e-8252-b3837a7ea469",
"name": "Sticky Note6",
"type": "n8n-nodes-base.stickyNote",
"position": [
-208,
-496
],
"parameters": {
"width": 208,
"height": 272,
"content": "save the information to the desired Google spreadsheet."
},
"typeVersion": 1
},
{
"parameters": {
"operation": "verify",
"email": "={{ $json.email || $json.Email }}",
"additionalOptions": {}
},
"type": "n8n-nodes-billionverify.billionVerify",
"typeVersion": 1,
"position": [
-1864,
-400
],
"name": "Verify Email (BillionVerify)",
"credentials": {
"billionVerifyApi": {
"id": "",
"name": "BillionVerify account"
}
}
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": true,
"leftValue": "",
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"id": "is-deliverable",
"leftValue": "={{ $json.is_deliverable }}",
"rightValue": "",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
}
}
]
}
},
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
-1684,
-400
],
"name": "IF deliverable"
}
],
"connections": {
"capture data": {
"main": [
[
{
"node": "processes information",
"type": "main",
"index": 0
}
]
]
},
"Search Emails": {
"main": [
[
{
"node": "search for an element in the email body",
"type": "main",
"index": 0
}
]
]
},
"open the link": {
"main": [
[
{
"node": "capture data",
"type": "main",
"index": 0
}
]
]
},
"set variables": {
"main": [
[
{
"node": "Save data in spreadsheet",
"type": "main",
"index": 0
}
]
]
},
"processes information": {
"main": [
[
{
"node": "set variables",
"type": "main",
"index": 0
}
]
]
},
"When clicking ‘Test workflow’": {
"main": [
[
{
"node": "Verify Email (BillionVerify)",
"type": "main",
"index": 0
}
]
]
},
"search for an element in the email body": {
"main": [
[
{
"node": "open the link",
"type": "main",
"index": 0
}
]
]
},
"Verify Email (BillionVerify)": {
"main": [
[
{
"node": "IF deliverable",
"type": "main",
"index": 0
}
]
]
},
"IF deliverable": {
"main": [
[
{
"node": "Search Emails",
"type": "main",
"index": 0
}
],
[]
]
}
},
"settings": {
"executionOrder": "v1"
}
}Workflow templates with Gmail
Ready-to-use workflows that verify emails before Gmail sends.
Verify emails before sending cold emails (Google Sheets → Gmail)
Verify before HubSpot deal-won welcome emails (HubSpot → Gmail)
Verify Facebook lead ads before auto-responding (Facebook → Gmail)
Verify before CRM follow-up emails (CRM → Gmail)
Verify before batch emails from a sheet (Google Sheets → Gmail)
Extract web page data from Gmail links and save to Google Sheets
How it works
- 1
Connect BillionVerify to your workflow using the n8n community node, Integrately's 1-click setup, or the REST API.
- 2
Add a verification step immediately before or after your Gmail trigger node collects or sends an email address.
- 3
BillionVerify checks syntax, domain health, SMTP reachability, disposable provider databases, and catch-all flags.
- 4
The result — valid, risky, or invalid — is returned as structured data your workflow can branch on.
- 5
Route verified addresses into Gmail sends or CRM records; discard or quarantine addresses that fail.
When to use this
Clean imported contact lists before outreach
Before sending a Gmail campaign or sequence to a newly imported list, run every address through BillionVerify to remove invalid, disposable, and role-based entries. Doing this upfront prevents hard bounces and keeps your sender score intact.
Validate form submissions in real time
When a lead submits a form and the contact lands in Gmail via a workflow trigger, verify the address instantly. Only confirmed addresses proceed to your inbox or CRM, stopping fake sign-ups before they clutter your pipeline.
Protect Gmail transactional sends
Automated confirmation and notification emails sent from Gmail-connected workflows waste quota and damage deliverability when addressed to bad emails. Verify recipients upstream so every transactional message counts.
FAQ
Does BillionVerify send a real email to verify an address?
No. Verification uses SMTP handshake probing and database checks without delivering any message, so recipients are never contacted during the process.
Can I verify addresses in bulk before a Gmail send?
Yes. Upload a list via the REST API or use the n8n bulk verification workflow to process thousands of addresses in one pass before triggering any Gmail sends.
What happens to catch-all addresses?
BillionVerify flags catch-all domains separately so you can decide whether to send, quarantine, or require additional confirmation rather than treating them as definitively valid or invalid.
Will verifying contacts affect my Gmail sending limits?
Verification happens outside Gmail entirely, through BillionVerify's API, so it has no impact on Gmail's daily sending quotas or rate limits.
Verify emails in Gmail
Create a free account, grab your API key, and stop bounces before they happen.
Get started free