This workflow corresponds to n8n.io template #16733 — we link there as the canonical source.
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 →
{
"id": "1bQcVqi4UPQA1P6z",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Bulk Email & Phone Finder from Names List [Tomba]",
"tags": [],
"nodes": [
{
"id": "bad1c672-326c-49fb-9f52-db17a3111ff4",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-608,
-336
],
"parameters": {
"width": 480,
"height": 832,
"content": "## Bulk Email & Phone Finder from Names List [Tomba]\n\n### How it works\n\nThis workflow runs on a schedule to process a list of pending contacts from Google Sheets. It loops through each contact, searches Tomba for an email address, conditionally looks up a phone number, formats the enrichment results, and writes them back to the sheet. After each update, it returns to the loop until all pending contacts are processed.\n\n### Setup steps\n\n- Connect Google Sheets credentials and configure the source spreadsheet/range for pending contacts.\n- Connect Tomba credentials/API key for email and phone lookup operations.\n- Ensure the sheet contains the required input columns, such as name, company, domain, or other fields used by the Tomba nodes.\n- Configure the update node to write results back to the correct row and output columns, such as email, phone, status, and timestamps.\n- Set the schedule trigger interval to match the desired processing frequency.\n\n### Customization\n\nAdjust the pending-contact filter, batch size, phone lookup condition, and formatting code to match your sheet structure and enrichment rules."
},
"typeVersion": 1
},
{
"id": "52af7da3-8be3-49d1-833d-70495d8a0024",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-48,
-96
],
"parameters": {
"color": 7,
"width": 640,
"height": 304,
"content": "## Load pending contacts\n\nStarts on a schedule, reads pending contact rows from Google Sheets, and prepares them for batch processing through the loop."
},
"typeVersion": 1
},
{
"id": "55243b55-c250-4c3f-9a8f-729819cbf59c",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
624,
-224
],
"parameters": {
"color": 7,
"width": 416,
"height": 336,
"content": "## Find email and branch\n\nUses Tomba to find an email address for each contact, then checks whether a phone lookup should be attempted or whether the data can move directly to formatting."
},
"typeVersion": 1
},
{
"id": "3f08ca70-ed65-48c4-ae29-b4eac2538e92",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
1072,
-336
],
"parameters": {
"color": 7,
"width": 640,
"height": 528,
"content": "## Format and update sheet\n\nOptionally finds a phone number with Tomba, formats the enriched contact data, updates the corresponding Google Sheets row, and returns control to the batch loop for the next contact."
},
"typeVersion": 1
},
{
"id": "b91fdcfc-b570-4216-8f19-5d25ceebbc43",
"name": "When Scheduled",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
0,
32
],
"parameters": {
"rule": {
"interval": [
{}
]
}
},
"typeVersion": 1.3
},
{
"id": "cff239b8-0260-4910-8f4c-434da9cb5ad8",
"name": "Read Contacts from Sheets",
"type": "n8n-nodes-base.googleSheets",
"position": [
224,
32
],
"parameters": {
"options": {},
"filtersUI": {
"values": [
{
"lookupValue": "Pending",
"lookupColumn": "Status"
}
]
},
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1apEcL-BPdGJVROh9fSpMNmsz_YK4csv90X2279jJOBs/edit#gid=0",
"cachedResultName": "domain names"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1apEcL-BPdGJVROh9fSpMNmsz_YK4csv90X2279jJOBs",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1apEcL-BPdGJVROh9fSpMNmsz_YK4csv90X2279jJOBs/edit?usp=drivesdk",
"cachedResultName": "Tomba - Bulk Contact Finder"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
},
{
"id": "97fb27c6-4223-4224-a985-a90768f870f9",
"name": "Loop Over Contact Batches",
"type": "n8n-nodes-base.splitInBatches",
"position": [
448,
32
],
"parameters": {
"options": {}
},
"typeVersion": 3
},
{
"id": "b3286290-cff6-4b82-a166-38361659df1f",
"name": "Search Email with Tomba",
"type": "n8n-nodes-tomba.tomba",
"position": [
672,
-48
],
"parameters": {
"domain": "={{ $json.Domain }}",
"company": "={{ $json.Company }}",
"lastname": "={{ $json['Last Name'] }}",
"resource": "email",
"firstname": "={{ $json['First Name'] }}"
},
"credentials": {
"tombaApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "6f247e46-0c31-495c-a7f1-1e811b7d002e",
"name": "Check Phone Availability",
"type": "n8n-nodes-base.if",
"position": [
896,
-48
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 3,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "c7049042-e571-40ea-872f-864cd1734c82",
"operator": {
"type": "boolean",
"operation": "equals"
},
"leftValue": "={{ $json.phone_number }}",
"rightValue": true
}
]
}
},
"typeVersion": 2.3
},
{
"id": "b8256981-76bd-49b1-be78-115ad707d648",
"name": "Search Phone with Tomba",
"type": "n8n-nodes-tomba.tomba",
"position": [
1120,
-176
],
"parameters": {
"email": "={{ $json.email }}",
"resource": "phone"
},
"credentials": {
"tombaApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "e97622ba-289a-4a6d-891d-c74df3f25f48",
"name": "Format Contacts with Code",
"type": "n8n-nodes-base.code",
"position": [
1360,
-32
],
"parameters": {
"jsCode": "const items = $input.all();\nconst results = [];\n\nfor (const item of items) {\n const json = item.json;\n\n // Check if phone data exists (came from phone finder node)\n const phoneNumber = json.phone_data && json.phone_data.length > 0\n ? json.phone_data[0].number\n : \"Not Found\";\n\n results.push({\n json: {\n email: json.email || \"Not Found\",\n phone: phoneNumber,\n first_name: json.first_name || \"\",\n last_name: json.last_name || \"\",\n full_name: json.full_name || \"\",\n company: json.company || \"\",\n score: json.score || 0,\n status: json.email ? \"Enriched\" : \"Not Found\"\n }\n });\n}\n\nreturn results;"
},
"typeVersion": 2
},
{
"id": "102d0ed0-b757-4456-a099-5a7502f4b901",
"name": "Update Sheets with Contacts",
"type": "n8n-nodes-base.googleSheets",
"position": [
1568,
32
],
"parameters": {
"columns": {
"value": {
"Email": "={{ $json.email }}",
"Phone": "={{ $json.phone }}",
"Score": "={{ $json.score }}",
"Status": "Done",
"row_number": "={{ $('Loop Over Contact Batches').item.json.row_number }}"
},
"schema": [
{
"id": "First Name",
"type": "string",
"display": true,
"required": false,
"displayName": "First Name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Last Name",
"type": "string",
"display": true,
"required": false,
"displayName": "Last Name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Company",
"type": "string",
"display": true,
"required": false,
"displayName": "Company",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Domain",
"type": "string",
"display": true,
"required": false,
"displayName": "Domain",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Status",
"type": "string",
"display": true,
"required": false,
"displayName": "Status",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Email",
"type": "string",
"display": true,
"required": false,
"displayName": "Email",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Phone",
"type": "string",
"display": true,
"required": false,
"displayName": "Phone",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Score",
"type": "string",
"display": true,
"required": false,
"displayName": "Score",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "row_number",
"type": "number",
"display": true,
"removed": false,
"readOnly": true,
"required": false,
"displayName": "row_number",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [
"row_number"
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "update",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1apEcL-BPdGJVROh9fSpMNmsz_YK4csv90X2279jJOBs/edit#gid=0",
"cachedResultName": "domain names"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1apEcL-BPdGJVROh9fSpMNmsz_YK4csv90X2279jJOBs",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1apEcL-BPdGJVROh9fSpMNmsz_YK4csv90X2279jJOBs/edit?usp=drivesdk",
"cachedResultName": "Tomba - Bulk Contact Finder"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
}
],
"active": false,
"settings": {
"binaryMode": "separate",
"availableInMCP": false,
"executionOrder": "v1"
},
"versionId": "72d39f11-8267-4c46-aa2c-011805ded8f6",
"connections": {
"When Scheduled": {
"main": [
[
{
"node": "Read Contacts from Sheets",
"type": "main",
"index": 0
}
]
]
},
"Search Email with Tomba": {
"main": [
[
{
"node": "Check Phone Availability",
"type": "main",
"index": 0
}
]
]
},
"Search Phone with Tomba": {
"main": [
[
{
"node": "Format Contacts with Code",
"type": "main",
"index": 0
}
]
]
},
"Check Phone Availability": {
"main": [
[
{
"node": "Search Phone with Tomba",
"type": "main",
"index": 0
}
],
[
{
"node": "Format Contacts with Code",
"type": "main",
"index": 0
}
]
]
},
"Format Contacts with Code": {
"main": [
[
{
"node": "Update Sheets with Contacts",
"type": "main",
"index": 0
}
]
]
},
"Loop Over Contact Batches": {
"main": [
[],
[
{
"node": "Search Email with Tomba",
"type": "main",
"index": 0
}
]
]
},
"Read Contacts from Sheets": {
"main": [
[
{
"node": "Loop Over Contact Batches",
"type": "main",
"index": 0
}
]
]
},
"Update Sheets with Contacts": {
"main": [
[
{
"node": "Loop Over Contact Batches",
"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.
googleSheetsOAuth2ApitombaApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow runs on a schedule to read “Pending” contacts from Google Sheets, uses Tomba to find email addresses and (when available) phone numbers, then writes the enriched results back to the same spreadsheet. Runs on a scheduled trigger. Reads rows from a Google Sheets…
Source: https://n8n.io/workflows/16733/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
This workflow automates video distribution to 9 social platforms simultaneously using Blotato's API. It includes both a scheduled publisher (checks Google Sheets for videos marked "Ready") and a subwo
YogiAI. Uses googleSheets, googleSheetsTool, httpRequest, stopAndError. Scheduled trigger; 61 nodes.
This workflow monitors Google Calendar for events indicating that a customer will visit the company today or the next day, retrieves the required details, and sends reminder notifications to the relev
Useful if a team is working within a single instance and you want to be notified of what workflows have changed since you last visited them. Another use-case might be monitoring your managed instances
ofn hook v0.24.0 beta. Uses start, httpRequest, functionItem, itemLists. Scheduled trigger; 42 nodes.