Personalized cold lead re-engagement with Zoho CRM and GPT-4o-mini
Pull contacts, verify each address with BillionVerify, and continue to Zoho CRM — only deliverable addresses get through.
Why verify before the send
Sending to invalid, risky, catch-all, or disposable addresses spikes your bounce rate and erodes sender reputation. A verification gate before the Zoho CRM step removes that risk automatically — only deliverable addresses continue, the rest are flagged.
The workflow
BillionVerify — verification sits right before the send.
Node by node
- 1Schedule: Mon/Wed/Fri 9AM1Trigger· n8n
Starts the workflow — on a schedule, a webhook, or manually while you test.
- 2GPT-4o Mini ModelSource· n8n
Provides or transforms the contact data flowing through the workflow.
- 3Calculate Date Ranges1Source· n8n
Provides or transforms the contact data flowing through the workflow.
- 4Fetch Cold Leads from ZohoSource· n8n
Provides or transforms the contact data flowing through the workflow.
- 5Process & Score Leads1Source· n8n
Provides or transforms the contact data flowing through the workflow.
- 6Filter High-Value Leads1Logic· n8n
Branches on the verification result: only deliverable addresses continue to the send; the rest are skipped and flagged.
- 7Tech Segment?1Logic· n8n
Branches on the verification result: only deliverable addresses continue to the send; the rest are skipped and flagged.
- 8Set Tech Segment1Source· n8n
Provides or transforms the contact data flowing through the workflow.
- 9Healthcare Segment?1Logic· n8n
Branches on the verification result: only deliverable addresses continue to the send; the rest are skipped and flagged.
- 10A/B Test Setup1Source· n8n
Provides or transforms the contact data flowing through the workflow.
- 11Set Healthcare Segment1Source· n8n
Provides or transforms the contact data flowing through the workflow.
- 12Set General Segment1Source· n8n
Provides or transforms the contact data flowing through the workflow.
- 13AI Email ComposerSource· n8n
Provides or transforms the contact data flowing through the workflow.
- 14Prepare Email Data1Source· n8n
Provides or transforms the contact data flowing through the workflow.
- 15Verify Email (BillionVerify)Verify· billionverify
The BillionVerify node verifies the address — status (valid / invalid / risky / catch-all / role / disposable), is_deliverable, and a confidence score — before anything is sent.
- 16IF deliverableLogic· n8n
Branches on the verification result: only deliverable addresses continue to the send; the rest are skipped and flagged.
- 17Send Email1Send· n8n
Sends only to verified, deliverable addresses. Swap in your own provider node if you send elsewhere.
- 18Check If SMS Needed1Logic· n8n
Branches on the verification result: only deliverable addresses continue to the send; the rest are skipped and flagged.
- 19Send SMS (HOT Leads)1Source· n8n
Provides or transforms the contact data flowing through the workflow.
- 20Update CRM Record1Source· n8n
Provides or transforms the contact data flowing through the workflow.
- 21Aggregate Campaign Stats1Source· n8n
Provides or transforms the contact data flowing through the workflow.
Workflow JSON
Copy or download this workflow, then import it in n8n (Workflows → Import from File / Paste). Install the BillionVerify community node first, then add your API key credential.
{
"name": "Personalized cold lead re-engagement with Zoho CRM and GPT-4o-mini + BillionVerify",
"nodes": [
{
"id": "b20b9460-99c7-42c0-b7c3-506838d45b1c",
"name": "Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-720,
2384
],
"parameters": {
"color": 7,
"content": "## Data Retrieval\nFetches leads from Zoho CRM that haven't been contacted in 30+ days. Returns lead details including contact info, scores, and activity history."
},
"typeVersion": 1
},
{
"id": "056fe6ef-df40-417e-96f9-ed2a930e3da8",
"name": "Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-336,
2272
],
"parameters": {
"color": 7,
"height": 192,
"content": "## Lead Scoring & Filtering\nCalculates engagement scores and priority tiers (HOT/WARM/COLD) based on inactivity. Filters out low-value leads (score <60)."
},
"typeVersion": 1
},
{
"id": "7c25f3fd-7bad-444a-9c28-219f9102828e",
"name": "Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
80,
2224
],
"parameters": {
"color": 7,
"height": 176,
"content": "## Industry Segmentation\nRoutes leads to Tech, Healthcare, or General segments for tailored messaging."
},
"typeVersion": 1
},
{
"id": "7067df96-8ada-41bd-ba59-271872500621",
"name": "Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
496,
2176
],
"parameters": {
"color": 7,
"width": 280,
"content": "## AI Personalization\nGenerates custom email content using GPT-4o based on lead profile, industry, and inactivity period. Sets up A/B test variants for subject lines."
},
"typeVersion": 1
},
{
"id": "0870ba0d-c6f4-45e1-b5f4-1f309697d0a7",
"name": "Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
1104,
2320
],
"parameters": {
"color": 7,
"width": 280,
"height": 176,
"content": "## Multi-Channel Outreach\nSends personalized emails to all qualified leads. HOT priority leads with phone numbers also receive SMS follow-ups via Twilio."
},
"typeVersion": 1
},
{
"id": "af94d270-7c04-48b4-98f4-f09cd94134b1",
"name": "Note6",
"type": "n8n-nodes-base.stickyNote",
"position": [
1536,
2224
],
"parameters": {
"color": 7,
"width": 280,
"height": 192,
"content": "## CRM Update & Analytics\nUpdates lead records in Zoho with outreach status and aggregates campaign metrics (segment performance, A/B results, priority breakdown)."
},
"typeVersion": 1
},
{
"id": "77e8c5ca-9b9e-4bc9-bf07-aeb1db8e82dd",
"name": "Schedule: Mon/Wed/Fri 9AM1",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-880,
2576
],
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression"
}
]
}
},
"typeVersion": 1.1
},
{
"id": "732e237d-57ad-4612-badb-2423e4659786",
"name": "Calculate Date Ranges1",
"type": "n8n-nodes-base.function",
"position": [
-672,
2576
],
"parameters": {
"functionCode": "const today = new Date();\nconst date30 = new Date(today);\ndate30.setDate(today.getDate() - 30);\nconst date60 = new Date(today);\ndate60.setDate(today.getDate() - 60);\nconst date90 = new Date(today);\ndate90.setDate(today.getDate() - 90);\n\nreturn [{ \n json: { \n dateMinus30: date30.toISOString().split('T')[0],\n dateMinus60: date60.toISOString().split('T')[0],\n dateMinus90: date90.toISOString().split('T')[0],\n today: today.toISOString().split('T')[0],\n batchId: `BATCH_${Date.now()}`\n } \n}];"
},
"typeVersion": 1
},
{
"id": "a06dd10c-da43-424e-a025-2b79d4d41248",
"name": "Process & Score Leads1",
"type": "n8n-nodes-base.function",
"position": [
-256,
2576
],
"parameters": {
"functionCode": "// Extract leads from response and add metadata\nconst leads = $input.all()[0].json.data || [];\n\nconst processedLeads = leads.map(lead => {\n const lastActivity = new Date(lead.Last_Activity_Time);\n const daysSinceContact = Math.floor((new Date() - lastActivity) / (1000 * 60 * 60 * 24));\n \n // Calculate priority tier\n let priorityTier;\n if (daysSinceContact >= 90) priorityTier = 'HOT';\n else if (daysSinceContact >= 60) priorityTier = 'WARM';\n else priorityTier = 'COLD';\n \n // Calculate engagement score\n const baseScore = lead.Lead_Score || 50;\n const timeDecay = Math.min(daysSinceContact / 30, 3) * 10;\n const engagementScore = Math.max(baseScore - timeDecay, 0);\n \n return {\n ...lead,\n daysSinceContact,\n priorityTier,\n engagementScore: Math.round(engagementScore),\n batchId: $('Calculate Date Ranges').item.json.batchId\n };\n});\n\nreturn processedLeads.map(lead => ({ json: lead }));"
},
"typeVersion": 1
},
{
"id": "af19df2d-7acc-49fa-9211-1db264f5b6ee",
"name": "Filter High-Value Leads1",
"type": "n8n-nodes-base.if",
"position": [
-64,
2576
],
"parameters": {
"conditions": {
"number": [
{
"value1": "={{ $json.engagementScore }}",
"value2": 60,
"operation": "largerEqual"
}
],
"string": [
{
"value1": "={{ $json.Email }}",
"operation": "isNotEmpty"
}
]
}
},
"typeVersion": 1
},
{
"id": "632af03e-8298-4881-8b11-9ee3cb864edd",
"name": "Tech Segment?1",
"type": "n8n-nodes-base.if",
"position": [
144,
2448
],
"parameters": {
"conditions": {
"string": [
{
"value1": "={{ $json.Industry }}",
"value2": "Technology|Software|IT Services",
"operation": "regex"
}
]
}
},
"typeVersion": 1
},
{
"id": "6fd53516-c2b7-48ee-8163-6c2b0e4f7163",
"name": "Healthcare Segment?1",
"type": "n8n-nodes-base.if",
"position": [
128,
2688
],
"parameters": {
"conditions": {
"string": [
{
"value1": "={{ $json.Industry }}",
"value2": "Healthcare|Medical|Pharma",
"operation": "regex"
}
]
}
},
"typeVersion": 1
},
{
"id": "400488a2-746e-4915-856c-b09defafadb5",
"name": "Set Tech Segment1",
"type": "n8n-nodes-base.set",
"position": [
352,
2368
],
"parameters": {
"values": {
"string": [
{
"name": "segment",
"value": "tech"
},
{
"name": "segmentName",
"value": "Technology"
}
]
},
"options": {}
},
"typeVersion": 1
},
{
"id": "307163e1-b1ca-4d22-9fc4-625f5a8af44f",
"name": "Set Healthcare Segment1",
"type": "n8n-nodes-base.set",
"position": [
352,
2576
],
"parameters": {
"values": {
"string": [
{
"name": "segment",
"value": "healthcare"
},
{
"name": "segmentName",
"value": "Healthcare"
}
]
},
"options": {}
},
"typeVersion": 1
},
{
"id": "6026ad91-9495-496d-b5fb-769eb67eb59e",
"name": "Set General Segment1",
"type": "n8n-nodes-base.set",
"position": [
352,
2784
],
"parameters": {
"values": {
"string": [
{
"name": "segment",
"value": "general"
},
{
"name": "segmentName",
"value": "General"
}
]
},
"options": {}
},
"typeVersion": 1
},
{
"id": "951fbe0b-e930-45dc-b895-bb3eb87f591d",
"name": "A/B Test Setup1",
"type": "n8n-nodes-base.set",
"position": [
544,
2576
],
"parameters": {
"values": {
"string": [
{
"name": "subjectLineVariant",
"value": "={{ Math.random() > 0.5 ? 'A' : 'B' }}"
},
{
"name": "subjectA",
"value": "Quick question about {{ $json.Company }}"
},
{
"name": "subjectB",
"value": "Let's reconnect - exciting update for {{ $json.Industry }}"
}
]
},
"options": {}
},
"typeVersion": 1
},
{
"id": "48ac77d4-d57d-4edd-b623-7bae1023d427",
"name": "Prepare Email Data1",
"type": "n8n-nodes-base.set",
"position": [
944,
2576
],
"parameters": {
"values": {
"string": [
{
"name": "emailBody",
"value": "={{ $json.text }}"
},
{
"name": "finalSubject",
"value": "={{ $json.subjectLineVariant === 'A' ? $json.subjectA : $json.subjectB }}"
},
{
"name": "sentAt",
"value": "={{ $now.toISO() }}"
}
]
},
"options": {}
},
"typeVersion": 1
},
{
"id": "2f8fc308-c67f-4731-a0c0-2c57abd99fff",
"name": "Send Email1",
"type": "n8n-nodes-base.emailSend",
"position": [
1152,
2576
],
"webhookId": "f7c375c0-1040-4ee3-8ae0-b6d1a4d10d58",
"parameters": {
"options": {},
"subject": "={{ $json.finalSubject }}",
"toEmail": "={{ $json.Email }}",
"fromEmail": "={{ $json.email }}"
},
"credentials": {
"smtp": {
"id": "credential-id",
"name": "smtp Credential"
}
},
"typeVersion": 2
},
{
"id": "1c9e4e6c-771e-4c0d-ac6d-64eb235ccc7c",
"name": "Check If SMS Needed1",
"type": "n8n-nodes-base.if",
"position": [
1344,
2576
],
"parameters": {
"conditions": {
"string": [
{
"value1": "={{ $json.Phone }}",
"operation": "isNotEmpty"
},
{
"value1": "={{ $json.priorityTier }}",
"value2": "HOT",
"operation": "equals"
}
]
}
},
"typeVersion": 1
},
{
"id": "6fc77d02-2bdf-4df1-8357-f83d57bfcee5",
"name": "Send SMS (HOT Leads)1",
"type": "n8n-nodes-base.httpRequest",
"position": [
1552,
2448
],
"parameters": {
"url": "https://api.twilio.com/2010-04-01/Accounts/YOUR_ACCOUNT_SID/Messages.json",
"method": "POST",
"options": {},
"sendBody": true,
"bodyParameters": {
"parameters": [
{}
]
}
},
"typeVersion": 3
},
{
"id": "4361c66e-ed0e-424f-997c-9c7f95323422",
"name": "Update CRM Record1",
"type": "n8n-nodes-base.httpRequest",
"position": [
1552,
2672
],
"parameters": {
"url": "https://www.zohoapis.in/crm/v2/Leads/{{ $json.id }}",
"method": "PUT",
"options": {},
"sendBody": true,
"bodyParameters": {
"parameters": [
{}
]
}
},
"typeVersion": 3
},
{
"id": "2af48046-d40b-49c8-8653-79d128015d8c",
"name": "Aggregate Campaign Stats1",
"type": "n8n-nodes-base.function",
"position": [
1744,
2576
],
"parameters": {
"functionCode": "// Aggregate campaign results\nconst items = $input.all();\nconst totalProcessed = items.length;\nconst bySegment = {};\nconst byPriority = {};\nconst byVariant = { A: 0, B: 0 };\n\nitems.forEach(item => {\n const data = item.json;\n \n // Count by segment\n bySegment[data.segment] = (bySegment[data.segment] || 0) + 1;\n \n // Count by priority\n byPriority[data.priorityTier] = (byPriority[data.priorityTier] || 0) + 1;\n \n // Count by A/B variant\n byVariant[data.subjectLineVariant]++;\n});\n\nconst avgEngagementScore = items.reduce((sum, item) => sum + (item.json.engagementScore || 0), 0) / totalProcessed;\n\nreturn [{\n json: {\n batchId: items[0].json.batchId,\n completedAt: new Date().toISOString(),\n totalLeadsProcessed: totalProcessed,\n segmentBreakdown: bySegment,\n priorityBreakdown: byPriority,\n abTestSplit: byVariant,\n averageEngagementScore: Math.round(avgEngagementScore),\n campaignType: 'Cold Lead Revival'\n }\n}];"
},
"typeVersion": 1
},
{
"id": "78b152cd-ed0a-4e25-abb4-3a0f03240d11",
"name": "Fetch Cold Leads from Zoho",
"type": "n8n-nodes-base.httpRequest",
"position": [
-480,
2576
],
"parameters": {
"url": "https://www.zohoapis.in/crm/v2/Leads/search?criteria=((Last_Activity_Time:before:{{$json[\"dateMinus30\"]}}))&fields=First_Name,Last_Name,Email,Phone,Company,Industry,Lead_Score,Lead_Status,Last_Activity_Time,Notes,Lead_Source&per_page=200",
"options": {}
},
"typeVersion": 3
},
{
"id": "8f6e2db6-ab4a-4e37-be3d-d0eec739afe0",
"name": "AI Email Composer",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
688,
2368
],
"parameters": {
"text": "=You are a sales expert crafting a re-engagement email.\n\nLead Information:\n- Name: {{ $json.First_Name }} {{ $json.Last_Name }}\n- Company: {{ $json.Company }}\n- Industry: {{ $json.segmentName }}\n- Days since contact: {{ $json.daysSinceContact }}\n- Lead Score: {{ $json.engagementScore }}\n- Priority: {{ $json.priorityTier }}\n- Last Status: {{ $json.Lead_Status }}\n- Lead Source: {{ $json.Lead_Source }}\n- Previous Notes: {{ $json.Notes || 'None' }}\n\nTask: Write a personalized, warm re-engagement email (150-200 words) that:\n1. References their industry ({{ $json.segmentName }}) with relevant insights\n2. Acknowledges the time gap naturally\n3. Provides value (industry trend, solution, or opportunity)\n4. Includes a soft, specific call-to-action\n5. Maintains a conversational, helpful tone\n\nDo NOT use generic templates. Make it feel like a genuine, personalized message from a human who remembers them.\n\nReturn ONLY the email body text, no subject line.",
"options": {
"systemMessage": "You are an expert sales copywriter specializing in authentic, personalized B2B outreach."
},
"promptType": "define"
},
"typeVersion": 1.6
},
{
"id": "1750d75b-87bb-46d8-9361-28ec81c75c78",
"name": "GPT-4o Mini Model",
"type": "@n8n/n8n-nodes-langchain.lmChatAzureOpenAi",
"position": [
752,
2768
],
"parameters": {
"model": "gpt-4o-mini",
"options": {
"maxTokens": 500,
"temperature": 0.7
}
},
"credentials": {
"azureOpenAiApi": {
"id": "credential-id",
"name": "azureOpenAiApi Credential"
}
},
"typeVersion": 1
},
{
"id": "7e1a64b8-3c5c-4910-93d4-83113da5f242",
"name": "Overview",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1376,
2336
],
"parameters": {
"width": 420,
"height": 476,
"content": "## Overview: Cold Lead Reviver\n\n**How it works:**\nThis workflow automatically re-engages cold leads from your Zoho CRM on a set schedule. It fetches leads inactive for 30+ days, scores them based on engagement history, segments by industry, and sends personalized AI-generated emails. High-priority leads (90+ days inactive) also receive SMS follow-ups. The workflow includes A/B testing for subject lines and tracks campaign performance.\n\n**Setup steps:**\n1. Configure Zoho CRM credentials in \"Fetch Cold Leads\" node\n2. Set up Azure OpenAI credentials in \"GPT-4o Mini Model\" node\n3. Add SMTP credentials in \"Send Email\" node\n4. (Optional) Configure Twilio credentials in \"Send SMS\" node for hot leads\n5. Adjust the schedule trigger to your preferred cadence\n6. Update industry segmentation rules if needed"
},
"typeVersion": 1
},
{
"parameters": {
"operation": "verify",
"email": "={{ $json.Email }}",
"additionalOptions": {}
},
"type": "n8n-nodes-billionverify.billionVerify",
"typeVersion": 1,
"position": [
792,
2576
],
"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": [
972,
2576
],
"name": "IF deliverable"
}
],
"connections": {
"Send Email1": {
"main": [
[
{
"node": "Check If SMS Needed1",
"type": "main",
"index": 0
}
]
]
},
"Tech Segment?1": {
"main": [
[
{
"node": "Set Tech Segment1",
"type": "main",
"index": 0
}
],
[
{
"node": "Healthcare Segment?1",
"type": "main",
"index": 0
}
]
]
},
"A/B Test Setup1": {
"main": [
[
{
"node": "AI Email Composer",
"type": "main",
"index": 0
}
]
]
},
"AI Email Composer": {
"main": [
[
{
"node": "Prepare Email Data1",
"type": "main",
"index": 0
}
]
]
},
"GPT-4o Mini Model": {
"ai_languageModel": [
[
{
"node": "AI Email Composer",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Set Tech Segment1": {
"main": [
[
{
"node": "A/B Test Setup1",
"type": "main",
"index": 0
}
]
]
},
"Update CRM Record1": {
"main": [
[
{
"node": "Aggregate Campaign Stats1",
"type": "main",
"index": 0
}
]
]
},
"Prepare Email Data1": {
"main": [
[
{
"node": "Verify Email (BillionVerify)",
"type": "main",
"index": 0
}
]
]
},
"Check If SMS Needed1": {
"main": [
[
{
"node": "Send SMS (HOT Leads)1",
"type": "main",
"index": 0
}
],
[
{
"node": "Update CRM Record1",
"type": "main",
"index": 0
}
]
]
},
"Healthcare Segment?1": {
"main": [
[
{
"node": "Set Healthcare Segment1",
"type": "main",
"index": 0
}
],
[
{
"node": "Set General Segment1",
"type": "main",
"index": 0
}
]
]
},
"Set General Segment1": {
"main": [
[
{
"node": "A/B Test Setup1",
"type": "main",
"index": 0
}
]
]
},
"Send SMS (HOT Leads)1": {
"main": [
[
{
"node": "Update CRM Record1",
"type": "main",
"index": 0
}
]
]
},
"Calculate Date Ranges1": {
"main": [
[
{
"node": "Fetch Cold Leads from Zoho",
"type": "main",
"index": 0
}
]
]
},
"Process & Score Leads1": {
"main": [
[
{
"node": "Filter High-Value Leads1",
"type": "main",
"index": 0
}
]
]
},
"Set Healthcare Segment1": {
"main": [
[
{
"node": "A/B Test Setup1",
"type": "main",
"index": 0
}
]
]
},
"Filter High-Value Leads1": {
"main": [
[
{
"node": "Tech Segment?1",
"type": "main",
"index": 0
}
]
]
},
"Fetch Cold Leads from Zoho": {
"main": [
[
{
"node": "Process & Score Leads1",
"type": "main",
"index": 0
}
]
]
},
"Schedule: Mon/Wed/Fri 9AM1": {
"main": [
[
{
"node": "Calculate Date Ranges1",
"type": "main",
"index": 0
}
]
]
},
"Verify Email (BillionVerify)": {
"main": [
[
{
"node": "IF deliverable",
"type": "main",
"index": 0
}
]
]
},
"IF deliverable": {
"main": [
[
{
"node": "Send Email1",
"type": "main",
"index": 0
}
],
[]
]
}
},
"settings": {
"executionOrder": "v1"
}
}When to use this
- Cleaning a list before a Zoho CRM send or sync.
- Protecting Zoho CRM deliverability and sender reputation.
- Keeping bounce rates low so your sending is never throttled.
FAQ
Why verify before sending in Zoho CRM?
Verifying first keeps your bounce rate low, which protects your sender reputation and your results.
How do I import this workflow?
Download the JSON, then in n8n go to Workflows → Import from File (or paste it). Install the BillionVerify community node and add your API key credential.
What happens to risky or catch-all addresses?
They are routed to the false branch and excluded from the send. You decide whether to retry, review, or drop them.
Add verification to your workflow
Create a free account, grab your API key, and stop bounces before they happen.
Get started free