This workflow corresponds to n8n.io template #9739 — we link there as the canonical source.
This workflow follows the Gmail Trigger → Google Sheets 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 →
{
"id": "jZ5YGjDrbtOvVOQU",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Intelligent Lead Qualification and Routing System with Multi-Channel Intake",
"tags": [],
"nodes": [
{
"id": "87b304de-91b5-45a3-bda0-901812662913",
"name": "Email Trigger",
"type": "n8n-nodes-base.gmailTrigger",
"position": [
4624,
3488
],
"parameters": {
"filters": {},
"pollTimes": {
"item": [
{
"mode": "everyMinute"
}
]
}
},
"credentials": {},
"typeVersion": 1.3
},
{
"id": "a65a643f-5daa-4a1b-9056-b475d15f088a",
"name": "Form Submission Webhook",
"type": "n8n-nodes-base.webhook",
"position": [
4624,
3680
],
"parameters": {
"path": "648db646-76c1-44b4-bab0-5955971721e5",
"options": {}
},
"typeVersion": 2.1
},
{
"id": "3bfe7c3d-3ffc-423e-98ac-882115871880",
"name": "Merge Inputs",
"type": "n8n-nodes-base.merge",
"position": [
4848,
3584
],
"parameters": {},
"typeVersion": 3.2
},
{
"id": "a6b72464-b3c4-4737-8205-9695b54def91",
"name": "Workflow Configuration",
"type": "n8n-nodes-base.set",
"position": [
5072,
3584
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "id-1",
"name": "targetIndustries",
"type": "string",
"value": "technology,software,saas,fintech,healthcare,manufacturing,retail,ecommerce"
},
{
"id": "id-2",
"name": "minCompanySize",
"type": "string",
"value": "100"
},
{
"id": "id-3",
"name": "buyerRoles",
"type": "string",
"value": "ceo,cto,cfo,vp,director,head,manager,founder,owner"
},
{
"id": "id-4",
"name": "taskDueHours",
"type": "string",
"value": "24"
},
{
"id": "id-5",
"name": "slackChannel",
"type": "string",
"value": "C1234567890"
},
{
"id": "id-6",
"name": "googleSheetUrl",
"type": "string",
"value": "https://docs.google.com/spreadsheets/d/YOUR_SHEET_ID/edit"
},
{
"id": "id-7",
"name": "crmSystem",
"type": "string",
"value": "hubspot"
},
{
"id": "id-8",
"name": "note",
"type": "string",
"value": "SETUP REQUIRED: Configure all parameters below with your specific values. This centralizes all workflow settings for easy maintenance."
}
]
},
"includeOtherFields": true
},
"typeVersion": 3.4
},
{
"id": "c27ff33d-3ffa-474b-9ce2-3a691b3099fb",
"name": "Validate Input Data",
"type": "n8n-nodes-base.code",
"position": [
5296,
3584
],
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "// Validate input data from email or form submission\nconst item = $input.item.json;\n\n// Initialize validation result\nlet isValid = true;\nlet errors = [];\n\n// Check for required fields\nif (!item.email && !item.text && !item.body && !item.content) {\n isValid = false;\n errors.push('Missing required field: email or text content');\n}\n\n// Validate email format if present\nif (item.email) {\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n if (!emailRegex.test(item.email)) {\n isValid = false;\n errors.push('Invalid email format');\n }\n}\n\n// Check for text content\nconst textContent = item.text || item.body || item.content || '';\nif (textContent.trim().length === 0) {\n isValid = false;\n errors.push('Missing text content');\n}\n\n// Return validation result\nreturn {\n ...item,\n validation: {\n isValid: isValid,\n errors: errors,\n timestamp: new Date().toISOString()\n }\n};",
"notice": "Validates incoming data to ensure required fields are present and properly formatted. Invalid data is routed to the failure logging branch."
},
"typeVersion": 2
},
{
"id": "e770dba1-d250-4af5-9286-c11e37b21c92",
"name": "Check Validation",
"type": "n8n-nodes-base.if",
"position": [
5520,
3584
],
"parameters": {
"options": {},
"conditions": {
"options": {
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "id-1",
"operator": {
"type": "boolean",
"operation": "equals"
},
"leftValue": "={{ $('Validate Input Data').item.json.validation.isValid }}",
"rightValue": true
}
]
}
},
"typeVersion": 2.2
},
{
"id": "cad2ba36-5c01-45c9-b018-2f6b02a5d0b4",
"name": "Parse AI Response",
"type": "n8n-nodes-base.code",
"position": [
6096,
3488
],
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "// Parse AI Response and extract structured lead data\n// Note: Parses AI response into structured fields for downstream processing\nconst aiResponse = $input.item.json;\n\n// If the AI response is a string, parse it as JSON\nlet leadData;\nif (typeof aiResponse === 'string') {\n try {\n leadData = JSON.parse(aiResponse);\n } catch (error) {\n // If parsing fails, try to extract JSON from the string\n const jsonMatch = aiResponse.match(/\\{[\\s\\S]*\\}/);\n if (jsonMatch) {\n leadData = JSON.parse(jsonMatch[0]);\n } else {\n throw new Error('Unable to parse AI response as JSON');\n }\n }\n} else {\n leadData = aiResponse;\n}\n\n// Extract and structure the lead data fields\nconst structuredLead = {\n firstName: leadData.firstName || leadData.first_name || '',\n lastName: leadData.lastName || leadData.last_name || '',\n email: leadData.email || '',\n phone: leadData.phone || leadData.phoneNumber || '',\n company: leadData.company || leadData.companyName || '',\n jobTitle: leadData.jobTitle || leadData.title || '',\n industry: leadData.industry || '',\n companySize: leadData.companySize || leadData.company_size || '',\n country: leadData.country || leadData.location || '',\n state: leadData.state || leadData.region || '',\n city: leadData.city || '',\n budget: leadData.budget || '',\n timeline: leadData.timeline || leadData.purchaseTimeline || '',\n painPoints: leadData.painPoints || leadData.pain_points || [],\n interests: leadData.interests || leadData.products_interested || [],\n source: leadData.source || 'unknown',\n notes: leadData.notes || leadData.additionalInfo || '',\n rawResponse: aiResponse\n};\n\nreturn structuredLead;"
},
"typeVersion": 2
},
{
"id": "c21948dc-f3c6-45e0-965a-84088865a7af",
"name": "Calculate Lead Score",
"type": "n8n-nodes-base.code",
"position": [
6320,
3488
],
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "// Calculate lead score using transparent rubric (0-100 points)\n// Scores leads 0-100 based on ICP criteria from Workflow Configuration: Industry Match (30pts), Company Size (25pts), Role Match (25pts), Problem Statement (10pts), Budget Signals (10pts). Categorizes as Hot (80+), Warm (60-79), Cold (40-59), or Unqualified (<40).\nconst item = $input.item.json;\n\n// Initialize scoring\nlet score = 0;\nlet breakdown = {};\nlet reasoning = [];\n\n// Target industries for scoring - read from Workflow Configuration\nconst targetIndustries = ($('Workflow Configuration').first().json.targetIndustries || '').toLowerCase().split(',').map(i => i.trim());\n\n// Buyer roles that indicate decision-making authority - read from Workflow Configuration\nconst buyerRoles = ($('Workflow Configuration').first().json.buyerRoles || '').toLowerCase().split(',').map(r => r.trim());\n\n// Budget signal keywords\nconst budgetSignals = ['budget', 'investment', 'funding', 'purchase', 'buy', 'pricing', 'cost', 'quote', 'proposal'];\n\n// 1. Industry Match (30 points)\nconst industry = (item.industry || '').toLowerCase();\nconst industryMatch = targetIndustries.some(target => industry.includes(target));\nif (industryMatch) {\n score += 30;\n breakdown.industry = 30;\n reasoning.push(`Industry \\\"${item.industry}\\\" matches target industries (+30 points)`);\n} else {\n breakdown.industry = 0;\n reasoning.push(`Industry \\\"${item.industry}\\\" does not match target industries (0 points)`);\n}\n\n// 2. Company Size (25 points)\nconst companySize = parseInt(item.companySize || item.company_size || 0);\nif (companySize >= 100) {\n score += 25;\n breakdown.companySize = 25;\n reasoning.push(`Company size ${companySize} meets minimum threshold (+25 points)`);\n} else if (companySize >= 50) {\n score += 15;\n breakdown.companySize = 15;\n reasoning.push(`Company size ${companySize} is moderate (+15 points)`);\n} else if (companySize >= 10) {\n score += 5;\n breakdown.companySize = 5;\n reasoning.push(`Company size ${companySize} is small (+5 points)`);\n} else {\n breakdown.companySize = 0;\n reasoning.push(`Company size ${companySize} is below threshold (0 points)`);\n}\n\n// 3. Role Match (25 points)\nconst role = (item.role || item.jobTitle || item.title || '').toLowerCase();\nconst roleMatch = buyerRoles.some(buyerRole => role.includes(buyerRole));\nif (roleMatch) {\n score += 25;\n breakdown.role = 25;\n reasoning.push(`Role \\\"${item.role || item.jobTitle || item.title}\\\" indicates decision-making authority (+25 points)`);\n} else {\n breakdown.role = 0;\n reasoning.push(`Role \\\"${item.role || item.jobTitle || item.title}\\\" does not indicate decision-making authority (0 points)`);\n}\n\n// 4. Clear Problem Statement (10 points)\nconst message = (item.message || item.description || item.problem || '').toLowerCase();\nconst hasProblemStatement = message.length > 50 && (message.includes('need') || message.includes('problem') || message.includes('challenge') || message.includes('looking for') || message.includes('help'));\nif (hasProblemStatement) {\n score += 10;\n breakdown.problemStatement = 10;\n reasoning.push('Clear problem statement provided (+10 points)');\n} else {\n breakdown.problemStatement = 0;\n reasoning.push('No clear problem statement (0 points)');\n}\n\n// 5. Budget Signals (10 points)\nconst hasBudgetSignals = budgetSignals.some(signal => message.includes(signal));\nif (hasBudgetSignals) {\n score += 10;\n breakdown.budgetSignals = 10;\n reasoning.push('Budget signals detected in message (+10 points)');\n} else {\n breakdown.budgetSignals = 0;\n reasoning.push('No budget signals detected (0 points)');\n}\n\n// Determine lead quality tier\nlet tier = '';\nif (score >= 80) {\n tier = 'Hot Lead';\n} else if (score >= 60) {\n tier = 'Warm Lead';\n} else if (score >= 40) {\n tier = 'Cold Lead';\n} else {\n tier = 'Unqualified';\n}\n\n// Return enriched data with scoring\nreturn {\n ...item,\n leadScore: score,\n leadTier: tier,\n scoreBreakdown: breakdown,\n scoreReasoning: reasoning,\n scoredAt: new Date().toISOString()\n};"
},
"typeVersion": 2
},
{
"id": "44b4da8a-8531-4ade-9a2f-ab36b72ad723",
"name": "Route by Territory",
"type": "n8n-nodes-base.switch",
"position": [
6544,
3472
],
"parameters": {
"rules": {
"values": [
{
"conditions": {
"options": {
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $('Workflow Configuration').first().json.crmSystem }}",
"rightValue": "hubspot"
}
]
}
},
{
"conditions": {
"options": {
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $('Workflow Configuration').first().json.crmSystem }}",
"rightValue": "salesforce"
}
]
}
}
]
},
"options": {
"fallbackOutput": "extra"
}
},
"typeVersion": 3.3
},
{
"id": "a21e9adb-f9cd-4777-b93b-90d83eebe5de",
"name": "Create HubSpot Contact",
"type": "n8n-nodes-base.hubspot",
"position": [
6768,
3392
],
"parameters": {
"email": "={{ $json.email }}",
"options": {},
"additionalFields": {
"firstName": "={{ $json.firstName }}",
"companyName": "={{ $json.companyName }}",
"customPropertiesUi": {
"customPropertiesValues": [
{
"value": "={{ $json.leadScore }}",
"property": "lead_score"
},
{
"value": "={{ $json.region }}",
"property": "region"
}
]
}
}
},
"typeVersion": 2.2
},
{
"id": "5a66f775-7468-4d26-a15e-656ee0bef1b4",
"name": "Create Salesforce Lead",
"type": "n8n-nodes-base.salesforce",
"position": [
6768,
3584
],
"parameters": {
"company": "={{ $json.companyName }}",
"lastname": "={{ $json.role }}",
"additionalFields": {
"email": "={{ $json.email }}",
"leadSource": "Web",
"description": "={{ $json.problemStatement }}"
}
},
"typeVersion": 1
},
{
"id": "32f7110b-6959-416c-9d81-97d6cca18c3e",
"name": "Post to Slack",
"type": "n8n-nodes-base.slack",
"position": [
6992,
3488
],
"parameters": {
"text": "New lead qualified",
"select": "channel",
"blocksUi": "=[\n {\n \"type\": \"section\",\n \"text\": {\n \"type\": \"mrkdwn\",\n \"text\": \"*New Lead Qualified*\\n\\n*Company:* {{ $json.companyName }}\\n*Lead Score:* {{ $json.leadScore }}/100\\n\\n*Score Breakdown:*\\n{{ $json.scoreReasoning }}\\n\\n*Next Best Action:*\\n{{ $json.nextBestAction }}\"\n }\n },\n {\n \"type\": \"actions\",\n \"elements\": [\n {\n \"type\": \"button\",\n \"text\": {\n \"type\": \"plain_text\",\n \"text\": \"Create intro email\"\n },\n \"action_id\": \"create_intro_email\",\n \"style\": \"primary\"\n }\n ]\n }\n]",
"channelId": {
"__rl": true,
"mode": "id",
"value": "={{ $('Workflow Configuration').first().json.slackChannel }}"
},
"messageType": "block",
"otherOptions": {}
},
"typeVersion": 2.3
},
{
"id": "a0a91663-c96c-4241-a68d-f23321485bc8",
"name": "Log to Google Sheets",
"type": "n8n-nodes-base.googleSheets",
"position": [
7216,
3488
],
"parameters": {
"operation": "appendOrUpdate",
"sheetName": {
"__rl": true,
"mode": "list",
"value": ""
},
"documentId": {
"__rl": true,
"mode": "url",
"value": "={{ $('Workflow Configuration').first().json.googleSheetUrl }}"
}
},
"credentials": {},
"typeVersion": 4.7
},
{
"id": "702156e9-9ea0-4c23-ba93-d0c1fbc7bd0d",
"name": "Log Validation Failure",
"type": "n8n-nodes-base.set",
"position": [
5808,
3680
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "id-1",
"name": "status",
"type": "string",
"value": "validation_failed"
},
{
"id": "id-2",
"name": "timestamp",
"type": "string",
"value": "={{ $now.toISO() }}"
},
{
"id": "id-3",
"name": "errorMessage",
"type": "string",
"value": "={{ $json.validation.errors }}"
},
{
"id": "id-4",
"name": "note",
"type": "string",
"value": "Formats validation failure data for logging"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "209c94df-6322-4966-a1f8-a8ceaba25dd4",
"name": "Log Failed Leads",
"type": "n8n-nodes-base.googleSheets",
"position": [
6096,
3680
],
"parameters": {
"operation": "appendOrUpdate",
"sheetName": {
"__rl": true,
"mode": "list",
"value": ""
},
"documentId": {
"__rl": true,
"mode": "url",
"value": "={{ $('Workflow Configuration').first().json.googleSheetUrl }}"
}
},
"credentials": {},
"typeVersion": 4.7
},
{
"id": "8b5cc002-3b62-494e-b255-9523f719f825",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
4544,
3208
],
"parameters": {
"color": 3,
"width": 1152,
"height": 632,
"content": "# \ud83d\udfe1 Intake & Configuration\n\n\n## Update workflow configuration node: complete all fields\n\n## Add Google credentials\n\n## Your Google Sheet needs two headings: Leads, Failed Leads"
},
"typeVersion": 1
},
{
"id": "daa43d30-6209-4176-8864-7eac0fbde1d6",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
5688,
3088
],
"parameters": {
"color": 5,
"width": 784,
"height": 752,
"content": "## \ud83e\udde0 AI Extraction & Scoring\n\n## Enter Open AI credentials \n\n## AI calculates the lead score based on company, size, industry, role, problem, region, budget\n\n## Lead scoring (0-100)\n \n\n## Failed lead validations are logged to separate Google Sheet "
},
"typeVersion": 1
},
{
"id": "e6abb887-5d52-4e87-a3b5-05b28da27d93",
"name": "Sticky Note - Routing",
"type": "n8n-nodes-base.stickyNote",
"position": [
6488,
3088
],
"parameters": {
"color": 6,
"width": 880,
"height": 656,
"content": "## \ud83d\udce8 Routing & Notifications\n\n## Add credentials for HubSpot or Salesforce\n\n## Add Slack credentials "
},
"typeVersion": 1
},
{
"id": "e5414e6c-3e26-4e49-9659-ba5a99034ced",
"name": "Extract Lead Data with AI",
"type": "@n8n/n8n-nodes-langchain.openAi",
"position": [
5744,
3488
],
"parameters": {
"modelId": {
"__rl": true,
"mode": "id",
"value": "gpt-4o-mini"
},
"options": {},
"messages": {
"values": [
{
"content": "=Extract lead information from the following input and return a structured JSON object.\n\nRequired fields:\n- firstName: First name of the contact\n- lastName: Last name of the contact \n- email: Email address\n- phone: Phone number\n- company: Company name\n- jobTitle: Job title or role\n- industry: Industry sector\n- companySize: Number of employees (numeric)\n- country: Country\n- state: State or region\n- city: City\n- budget: Budget information or signals\n- timeline: Purchase timeline or urgency\n- painPoints: Array of pain points or challenges mentioned\n- interests: Array of products/services interested in\n- source: Source of the lead (email or form)\n\nInput data:\n={{ JSON.stringify($json) }}"
}
]
},
"jsonOutput": true
},
"credentials": {},
"typeVersion": 1.8
}
],
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "c71b55ca-3ccb-472b-8376-2d40d6c07a61",
"connections": {
"Merge Inputs": {
"main": [
[
{
"node": "Workflow Configuration",
"type": "main",
"index": 0
}
]
]
},
"Email Trigger": {
"main": [
[
{
"node": "Merge Inputs",
"type": "main",
"index": 0
}
]
]
},
"Post to Slack": {
"main": [
[
{
"node": "Log to Google Sheets",
"type": "main",
"index": 0
}
]
]
},
"Check Validation": {
"main": [
[
{
"node": "Extract Lead Data with AI",
"type": "main",
"index": 0
}
],
[
{
"node": "Log Validation Failure",
"type": "main",
"index": 0
}
]
]
},
"Parse AI Response": {
"main": [
[
{
"node": "Calculate Lead Score",
"type": "main",
"index": 0
}
]
]
},
"Route by Territory": {
"main": [
[
{
"node": "Create HubSpot Contact",
"type": "main",
"index": 0
}
],
[
{
"node": "Create Salesforce Lead",
"type": "main",
"index": 0
}
]
]
},
"Validate Input Data": {
"main": [
[
{
"node": "Check Validation",
"type": "main",
"index": 0
}
]
]
},
"Calculate Lead Score": {
"main": [
[
{
"node": "Route by Territory",
"type": "main",
"index": 0
}
]
]
},
"Create HubSpot Contact": {
"main": [
[
{
"node": "Post to Slack",
"type": "main",
"index": 0
}
]
]
},
"Create Salesforce Lead": {
"main": [
[
{
"node": "Post to Slack",
"type": "main",
"index": 0
}
]
]
},
"Log Validation Failure": {
"main": [
[
{
"node": "Log Failed Leads",
"type": "main",
"index": 0
}
]
]
},
"Workflow Configuration": {
"main": [
[
{
"node": "Validate Input Data",
"type": "main",
"index": 0
}
]
]
},
"Form Submission Webhook": {
"main": [
[
{
"node": "Merge Inputs",
"type": "main",
"index": 1
}
]
]
},
"Extract Lead Data with AI": {
"main": [
[
{
"node": "Parse AI Response",
"type": "main",
"index": 0
}
]
]
}
}
}
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
It extracts key business information using AI, scores the lead based on your ideal customer profile, creates CRM records, notifies your team on Slack, and logs all activity—including failures—to Google Sheets.
Source: https://n8n.io/workflows/9739/ — 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.
Who is this for? Event sales teams & conference organizers processing 100+ sponsor/partner emails weekly who need instant lead qualification, Salesforce automation, & pipeline analytics. _
Email Sentiment Router for Event Sales Leads
This template is perfect for: Marketing Teams looking to automatically qualify inbound leads from campaigns Sales Teams wanting to prioritize high-value prospects instantly Agencies offering lead qual
This n8n workflow automates end-to-end lead generation, from scraping local businesses to qualifying and sending high-quality prospects directly into your CRM.
Who is this for? Event organizers, RevOps teams, sales managers, and marketers running conferences, webinars, or meetups who want to automatically qualify RSVPs and turn attendees into revenue opportu