Highlevel email verification with BillionVerify
HighLevel is an all-in-one marketing automation and CRM platform used by agencies and businesses to manage contacts, run email and SMS campaigns, and automate sales pipelines. BillionVerify integrates to validate contact emails at every entry point, protecting campaign deliverability across the entire platform.
Why verify before the send
HighLevel consolidates contacts from forms, funnels, and third-party imports, making it easy for invalid and disposable addresses to accumulate across multiple sub-accounts. Verifying emails before they enter workflows prevents bounce-driven domain penalties, ensures automations trigger only for reachable contacts, and keeps your agency's sending reputation strong across all client accounts.
Ready-to-use n8n workflow
Import this workflow into n8n β it verifies every address with BillionVerify before Highlevel sends, so only deliverable contacts are emailed. Install the BillionVerify community node first, then add your API key. Adapted from this n8n template
{
"name": "Automate client renewal alerts from GoHighLevel to Gmail, Slack & Google Sheets + BillionVerify",
"nodes": [
{
"id": "e89a6dcb-42d4-4674-bd3d-2f91b86231b2",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-3120,
-64
],
"parameters": {
"color": 4,
"width": 420,
"height": 656,
"content": "## π Client Retention Renewal Reminder Workflow\n\nAutomatically identifies clients with contracts expiring within 10 days and sends personalized renewal reminders.\n\n### What This Workflow Does:\n- **Runs daily at 9 AM** to check for expiring contracts\n- **Fetches all contacts** from GoHighLevel CRM\n- **Filters clients** whose contracts expire in 0-10 days\n- **Sends renewal emails** to clients via Gmail\n- **Notifies account managers** via Slack\n- **Logs all activities** to Google Sheets for tracking\n\n### Business Benefits:\n- β
Never miss a renewal opportunity\n- β
Improve client retention rates\n- β
Automate manual follow-up tasks\n- β
Track renewal campaign effectiveness\n\n### Requirements:\n- GoHighLevel account with custom fields:\n - Contract End Date field\n - Account Manager field\n- Gmail account for sending emails\n- Slack workspace for notifications\n- Google Sheets for logging"
},
"typeVersion": 1
},
{
"id": "9ffba3e1-2389-47df-8257-708871c6c5e4",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2656,
-208
],
"parameters": {
"color": 5,
"width": 280,
"height": 240,
"content": "## β° Schedule Trigger Setup\n\nRuns daily at 9:00 AM server time.\n\n**Configuration:**\n- Cron: `0 9 * * *`\n- Frequency: Every day\n- Time: 9:00 AM\n\n**Why 9 AM?**\nEarly morning execution ensures:\n- Emails arrive during business hours\n- Account managers have full day to respond\n- Prevents weekend/holiday issues"
},
"typeVersion": 1
},
{
"id": "94e0e170-fe29-42a6-9926-d052fbc28fd5",
"name": "Schedule Daily at 9 AM",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-2560,
48
],
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "0 9 * * *"
}
]
}
},
"typeVersion": 1.1
},
{
"id": "05b63bb3-1942-4f24-9d53-3b3f2a25a7f5",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2432,
240
],
"parameters": {
"color": 5,
"width": 280,
"height": 396,
"content": "## π₯ Fetch Contacts from CRM\n\n**Setup Instructions:**\n1. Connect your GoHighLevel account\n2. Set limit to 50 (or adjust based on needs)\n3. Ensure API permissions include contact read access\n\n**Required Custom Fields:**\n- Contract End Date (Date field)\n- Account Manager (Text field)\n\n**Note:** Increase limit if you have more than 50 active clients"
},
"typeVersion": 1
},
{
"id": "5e3e0e62-267e-4728-a4ae-f92581607f06",
"name": "Fetch Contacts from GoHighLevel",
"type": "n8n-nodes-base.highLevel",
"position": [
-2336,
48
],
"parameters": {
"filters": {},
"options": {},
"operation": "getAll",
"requestOptions": {}
},
"credentials": {
"highLevelOAuth2Api": {
"id": "credential-id",
"name": "highLevelOAuth2Api Credential"
}
},
"typeVersion": 2
},
{
"id": "9e665b65-003d-430d-a7f7-48228b7dcad8",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2208,
-272
],
"parameters": {
"color": 5,
"width": 260,
"height": 292,
"content": "## π Validate Data Quality\n\nEnsures contacts have custom fields before processing.\n\n**Why This Matters:**\n- Prevents errors in downstream nodes\n- Filters out incomplete contact records\n- Improves workflow reliability"
},
"typeVersion": 1
},
{
"id": "eb37756d-3de4-4d63-8215-b4e8520bcb5e",
"name": "Check Has Custom Fields",
"type": "n8n-nodes-base.if",
"position": [
-2112,
48
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "58341a8d-2417-47e1-b29b-be575b270c35",
"operator": {
"type": "array",
"operation": "notEmpty",
"singleValue": true
},
"leftValue": "={{ $json.customFields }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2.2
},
{
"id": "f102174e-cba7-4d13-a322-f2327d9f1449",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1936,
208
],
"parameters": {
"color": 5,
"width": 280,
"height": 404,
"content": "## π― Filter Expiring Contracts\n\n**Logic:**\n- Finds Contract End Date field\n- Calculates days until expiry\n- Filters: 0-10 days remaining\n\n**Customization:**\nChange `daysUntilExpiry <= 10` to adjust reminder window:\n- 7 days = 1 week notice\n- 14 days = 2 weeks notice\n- 30 days = 1 month notice\n\n**Important:** Update field IDs to match YOUR GoHighLevel custom fields"
},
"typeVersion": 1
},
{
"id": "6f9a5a69-8ce9-46c1-88f2-d12a44a3f319",
"name": "Filter Renewals Code",
"type": "n8n-nodes-base.code",
"position": [
-1888,
48
],
"parameters": {
"jsCode": "// Get current date at midnight for accurate day comparison\nconst today = new Date();\ntoday.setHours(0, 0, 0, 0);\n\n// Array to store filtered contacts\nconst filteredContacts = [];\n\n// Process each contact from input\nfor (const contact of $input.all()) {\n const item = contact.json;\n \n // Check if contact has customFields\n if (!item.customFields || !Array.isArray(item.customFields)) {\n continue;\n }\n \n // TODO: Replace with YOUR custom field ID for Contract End Date\n const contractEndField = item.customFields.find(\n field => field.id === 'YOUR_CONTRACT_END_DATE_FIELD_ID'\n );\n \n // Skip if no contract end date exists\n if (!contractEndField || !contractEndField.value) {\n continue;\n }\n \n // Parse contract end date (timestamp in milliseconds)\n const contractEndDate = new Date(contractEndField.value);\n contractEndDate.setHours(0, 0, 0, 0);\n \n // Calculate days until expiry\n const daysUntilExpiry = Math.ceil(\n (contractEndDate - today) / (1000 * 60 * 60 * 24)\n );\n \n // Filter: expires within next 10 days (0-10 days)\n if (daysUntilExpiry >= 0 && daysUntilExpiry <= 10) {\n \n // TODO: Replace with YOUR custom field ID for Account Manager\n const accountManagerField = item.customFields.find(\n field => field.id === 'YOUR_ACCOUNT_MANAGER_FIELD_ID'\n );\n \n // Format the contract end date for display\n const formattedDate = contractEndDate.toLocaleDateString('en-US', {\n year: 'numeric',\n month: 'long',\n day: 'numeric'\n });\n \n // Create enriched contact object\n filteredContacts.push({\n json: {\n // Original contact data\n id: item.id,\n contactName: item.contactName,\n firstName: item.firstName || 'N/A',\n lastName: item.lastName || 'N/A',\n email: item.email || 'No email on file',\n companyName: item.companyName || 'N/A',\n phone: item.phone,\n \n // Contract information\n contractEndDate: formattedDate,\n contractEndDateRaw: contractEndDate.toISOString(),\n contractEndTimestamp: contractEndField.value,\n daysUntilExpiry: daysUntilExpiry,\n \n // Account manager info\n accountManager: accountManagerField?.value || 'Unassigned',\n \n // Additional fields for workflow\n allCustomFields: item.customFields,\n tags: item.tags || [],\n source: item.source\n }\n });\n }\n}\n\n// Return filtered contacts\nreturn filteredContacts;"
},
"typeVersion": 2
},
{
"id": "6f7a46e5-115c-4bef-9cc7-e30b96b1b94d",
"name": "Verify Expiring Within 10 Days",
"type": "n8n-nodes-base.filter",
"position": [
-1664,
48
],
"parameters": {
"conditions": {
"number": [
{
"value1": "={{ $json.daysUntilExpiry }}",
"value2": 10,
"operation": "smallerEqual"
}
],
"string": [
{
"value1": "={{ $json.contractEndDate }}",
"operation": "isNotEmpty"
}
]
}
},
"typeVersion": 1
},
{
"id": "3b9392da-852b-4692-bfac-5c177bbda695",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1536,
-400
],
"parameters": {
"color": 5,
"width": 280,
"height": 340,
"content": "## π§ Send Client Email\n\n**Setup:**\n1. Connect Gmail account\n2. Replace recipient with: `={{ $json.email }}`\n3. Customize email template\n\n**Email Variables:**\n- `firstName` - Client first name\n- `lastName` - Client last name\n- `contractEndDate` - Formatted expiry date\n- `companyName` - Company name\n\n**Best Practice:** Test email with your own address first"
},
"typeVersion": 1
},
{
"id": "17f722d7-781c-41d4-bd15-b84b187df947",
"name": "Send Renewal Email via Gmail",
"type": "n8n-nodes-base.gmail",
"position": [
-1440,
-48
],
"webhookId": "c62251a2-e50a-4f59-8e3e-d35403ca9d82",
"parameters": {
"sendTo": "={{ $json.email }}",
"message": "=Hi {{ $json.firstName }} {{ $json.lastName }},\n\nThis is a friendly reminder that your contract with us is set to expire on {{ $json.contractEndDate }}.\n\nWe'd love to continue working with you! Please let us know if you'd like to discuss renewal options.\n\nYour account manager will be reaching out shortly.\n\nBest regards,\nYour Team",
"options": {},
"subject": "Important: Your Contract Renewal is Coming Up"
},
"typeVersion": 2.1
},
{
"id": "3e716197-e31d-49d9-8c3e-b1ba215bed06",
"name": "Sticky Note6",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1488,
304
],
"parameters": {
"color": 5,
"width": 280,
"height": 384,
"content": "## π’ Slack Team Notification\n\n**Setup:**\n1. Connect Slack workspace\n2. Select channel for renewal alerts\n3. Customize message format\n\n**Recommended Channels:**\n- #renewals\n- #account-management\n- #sales-alerts\n\n**Note:** Ensure all account managers have access to the selected channel"
},
"typeVersion": 1
},
{
"id": "79b9f0dd-1fd1-4562-b93e-99e3bc111aeb",
"name": "Send Slack Alert to Team",
"type": "n8n-nodes-base.slack",
"position": [
-1440,
144
],
"webhookId": "2d02c3a0-61c7-4742-b2d5-665e3ad8dab8",
"parameters": {
"text": "=π *Contract Renewal Alert*\n\n*Client:* {{ $json.firstName }} {{ $json.lastName }}\n*Email:* {{ $json.email }}\n*Company:* {{ $json.companyName || \"N/A\" }}\n*Contract Expires:* {{ $json.contractEndDate }}\n*Days Remaining:* {{ $json.daysUntilExpiry }}\n*Account Manager:* {{ $json.accountManager }}\n\nβ
Renewal email has been sent to client.\nπ Please follow up within 3 business days.",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "list",
"value": "YOUR_SLACK_CHANNEL_ID",
"cachedResultName": "Select your renewals channel"
},
"otherOptions": {}
},
"typeVersion": 2.1
},
{
"id": "f3448850-b573-416a-b34c-8e1e7d985151",
"name": "Merge Email and Slack Results",
"type": "n8n-nodes-base.merge",
"position": [
-1216,
48
],
"parameters": {
"mode": "combine",
"options": {},
"combinationMode": "mergeByPosition"
},
"typeVersion": 2.1
},
{
"id": "96ae9e61-3ffc-4f04-b6ac-2a58495dc455",
"name": "Sticky Note7",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1072,
-272
],
"parameters": {
"color": 5,
"width": 260,
"height": 296,
"content": "## π Generate Summary Report\n\nCreates execution summary with:\n- Total reminders sent\n- Timestamp of execution\n- Success status\n\n**Used for:**\n- Tracking workflow performance\n- Logging to Google Sheets\n- Debugging issues"
},
"typeVersion": 1
},
{
"id": "c61d0e08-0b24-4be6-bbcd-b58de927212a",
"name": "Generate Summary Report",
"type": "n8n-nodes-base.code",
"position": [
-992,
48
],
"parameters": {
"jsCode": "const totalReminders = $input.all().length;\nconst timestamp = new Date().toLocaleString();\n\nreturn {\n json: {\n summary: `Renewal Reminder Workflow Completed`,\n totalRemindersSent: totalReminders,\n timestamp: timestamp,\n message: `${totalReminders} renewal reminder(s) sent successfully on ${timestamp}`\n }\n};"
},
"typeVersion": 2
},
{
"id": "9e39598a-d4f0-43e9-9885-a306371772e1",
"name": "Sticky Note8",
"type": "n8n-nodes-base.stickyNote",
"position": [
-752,
256
],
"parameters": {
"color": 5,
"width": 280,
"height": 268,
"content": "## π Log to Google Sheets\n\n**Setup:**\n1. Create a Google Sheet for tracking\n2. Add columns: summary, totalRemindersSent, timestamp, message\n3. Connect your Google account\n4. Select your spreadsheet and sheet\n\n"
},
"typeVersion": 1
},
{
"id": "ace3170b-c470-4458-b601-db08918f1572",
"name": "Log Results to Google Sheets",
"type": "n8n-nodes-base.googleSheets",
"position": [
-768,
48
],
"parameters": {
"columns": {
"value": {},
"schema": [
{
"id": "summary",
"type": "string",
"display": true,
"required": false,
"displayName": "summary",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "totalRemindersSent",
"type": "string",
"display": true,
"required": false,
"displayName": "totalRemindersSent",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "timestamp",
"type": "string",
"display": true,
"required": false,
"displayName": "timestamp",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "message",
"type": "string",
"display": true,
"required": false,
"displayName": "message",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "autoMapInputData",
"matchingColumns": []
},
"options": {},
"operation": "appendOrUpdate",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "Sheet1",
"cachedResultName": "Select sheet name"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "YOUR_GOOGLE_SHEET_ID",
"cachedResultName": "Select your tracking sheet"
}
},
"typeVersion": 4.7
},
{
"parameters": {
"operation": "verify",
"email": "={{ $json.email }}",
"additionalOptions": {}
},
"type": "n8n-nodes-billionverify.billionVerify",
"typeVersion": 1,
"position": [
-1800,
-48
],
"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": [
-1620,
-48
],
"name": "IF deliverable"
}
],
"connections": {
"Filter Renewals Code": {
"main": [
[
{
"node": "Verify Expiring Within 10 Days",
"type": "main",
"index": 0
}
]
]
},
"Schedule Daily at 9 AM": {
"main": [
[
{
"node": "Fetch Contacts from GoHighLevel",
"type": "main",
"index": 0
}
]
]
},
"Check Has Custom Fields": {
"main": [
[
{
"node": "Filter Renewals Code",
"type": "main",
"index": 0
}
]
]
},
"Generate Summary Report": {
"main": [
[
{
"node": "Log Results to Google Sheets",
"type": "main",
"index": 0
}
]
]
},
"Send Slack Alert to Team": {
"main": [
[
{
"node": "Merge Email and Slack Results",
"type": "main",
"index": 1
}
]
]
},
"Send Renewal Email via Gmail": {
"main": [
[
{
"node": "Merge Email and Slack Results",
"type": "main",
"index": 0
}
]
]
},
"Merge Email and Slack Results": {
"main": [
[
{
"node": "Generate Summary Report",
"type": "main",
"index": 0
}
]
]
},
"Verify Expiring Within 10 Days": {
"main": [
[
{
"node": "Verify Email (BillionVerify)",
"type": "main",
"index": 0
},
{
"node": "Send Slack Alert to Team",
"type": "main",
"index": 0
}
]
]
},
"Fetch Contacts from GoHighLevel": {
"main": [
[
{
"node": "Check Has Custom Fields",
"type": "main",
"index": 0
}
]
]
},
"Verify Email (BillionVerify)": {
"main": [
[
{
"node": "IF deliverable",
"type": "main",
"index": 0
}
]
]
},
"IF deliverable": {
"main": [
[
{
"node": "Send Renewal Email via Gmail",
"type": "main",
"index": 0
}
],
[]
]
}
},
"settings": {
"executionOrder": "v1"
}
}Workflow templates with Highlevel
Ready-to-use workflows that verify emails before Highlevel sends.
How it works
- 1
A contact enters HighLevel through a form, funnel, manual import, or third-party sync.
- 2
An n8n community node or Integrately action triggers a BillionVerify check on the submitted email address.
- 3
BillionVerify performs SMTP verification, disposable-domain detection, and role-address filtering.
- 4
Contacts with valid emails proceed into HighLevel workflows; those with risky addresses are tagged or excluded.
- 5
Email campaigns and automations run against a cleaner list, reducing bounces and preserving sender reputation.
When to use this
Validate funnel form submissions in real time
When a lead submits a HighLevel funnel form, pass the email to BillionVerify before the contact is created. This stops invalid addresses from entering nurture sequences and prevents automated follow-up emails from bouncing.
Clean imported contact lists before bulk campaigns
Before launching an email broadcast to a large HighLevel contact list, export the addresses, verify them in bulk via the BillionVerify REST API, and re-import only valid contacts. This protects your domain from high bounce rates on cold campaigns.
Verify leads across agency sub-accounts centrally
Set up a shared BillionVerify n8n workflow that validates inbound leads from all client sub-accounts. Standardize list quality for every agency client without manual effort per account.
FAQ
Can BillionVerify work across multiple HighLevel sub-accounts?
Yes. Build a central n8n workflow that receives webhooks from multiple sub-accounts and routes each email through BillionVerify. The verified result can be written back to the originating sub-account via the HighLevel API.
How does email verification protect my agency's sending domain?
High bounce rates signal to mailbox providers that you are sending to poor-quality lists. BillionVerify removes invalid addresses before they reach your campaigns, keeping bounce rates low and your domain reputation intact.
Does BillionVerify detect role addresses like support@ or noreply@?
Yes. Role addresses rarely belong to a real individual and often have poor engagement. BillionVerify flags them so you can decide whether to include them in your HighLevel contact workflows.
What integration methods are available for HighLevel?
You can use the BillionVerify n8n community node, a one-click Integrately automation, or call the BillionVerify REST API directly from a HighLevel custom webhook or external automation.
Verify emails in Highlevel
Create a free account, grab your API key, and stop bounces before they happen.
Get started free