This workflow corresponds to n8n.io template #13740 — we link there as the canonical source.
This workflow follows the Datatable → Gmail 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": "a4DNO6qBBfDLN51C",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Email Sentiment for Event Sales Lead Routing TEMPLATE",
"tags": [],
"nodes": [
{
"id": "c4d6f602-a8c2-422c-968d-b840225f9b18",
"name": "Analyze Email Sentiment",
"type": "@n8n/n8n-nodes-langchain.sentimentAnalysis",
"maxTries": 2,
"position": [
-880,
288
],
"parameters": {
"options": {
"categories": "Positive, Neutral, Negative",
"enableAutoFixing": false,
"systemPromptTemplate": "You are a highly accurate sentiment analyzer specialized in the events and conferences industry. Analyze the sentiment of incoming emails related to event sponsorship, exhibition, attendance, speaking opportunities, vendor partnerships, and general event inquiries.\n\nCategorize each email into EXACTLY ONE of these categories: {categories}\n\n**Positive**: The sender shows clear interest, enthusiasm, or intent to sponsor, exhibit, attend, speak, or partner. They are asking about pricing, availability, packages, or next steps. Includes referrals, warm introductions, and repeat clients.\n\n**Neutral**: The sender is gathering information, asking general questions, requesting brochures or agendas, or has not yet indicated clear buying intent. Includes early-stage inquiries and informational requests.\n\n**Negative**: The sender is declining, canceling, expressing dissatisfaction, complaining about pricing, withdrawing interest, or making unfavorable comparisons to competitor events. Includes cancellation requests and negative feedback.\n\nIMPORTANT: Evaluate sentiment relative to OUR event/company. If the sender is negative about a competitor but positive toward us, classify as Positive. Focus on buying intent and business relationship signals.\n\nYOU MUST CHOOSE EXACTLY ONE CATEGORY!\nUse the provided formatting instructions.",
"includeDetailedResults": true
},
"inputText": "={{ $json.text || $json.input }}"
},
"retryOnFail": true,
"typeVersion": 1.1,
"waitBetweenTries": 1000
},
{
"id": "0b7151d8-b601-4dba-aac6-e558a98f78ed",
"name": "Send Hot Lead Email",
"type": "n8n-nodes-base.gmail",
"position": [
432,
288
],
"parameters": {
"sendTo": "user@example.com",
"message": "=<h2>\ud83d\udd25 High-Interest Event Lead Detected</h2>\n\n<p><strong>Sentiment:</strong> {{ $('Analyze Email Sentiment').item.json.sentimentAnalysis.category }}</p>\n<p><strong>Confidence:</strong> {{ $('Analyze Email Sentiment').item.json.sentimentAnalysis.confidence || 'N/A' }}</p>\n\n<hr>\n\n<h3>Original Email</h3>\n<p><strong>From:</strong> {{ $('Monitor Gmail Inbox').item.json.from }}</p>\n<p><strong>Subject:</strong> {{ $('Monitor Gmail Inbox').item.json.subject }}</p>\n<p><strong>Date:</strong> {{ $('Monitor Gmail Inbox').item.json.date }}</p>\n\n<blockquote>{{ $('Monitor Gmail Inbox').item.json.text }}</blockquote>\n\n<hr>\n\n<p><strong>Recommended Action:</strong> Prioritize immediate outreach. This contact is showing strong buying signals for event sponsorship, exhibition, or attendance. Respond within 2 hours for best conversion.</p>\n\n<p><em>\u2014 Email Sentiment Router | Braia Labs</em></p>",
"options": {
"appendAttribution": false
},
"subject": "=\ud83d\udd25 Hot Lead \u2014 {{ $('Monitor Gmail Inbox').item.json.subject }}"
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
},
"typeVersion": 2.1
},
{
"id": "24ba0ed5-e82c-497c-9606-63373c2744cc",
"name": "Monitor Gmail Inbox",
"type": "n8n-nodes-base.gmailTrigger",
"position": [
-1344,
304
],
"parameters": {
"simple": false,
"filters": {},
"options": {},
"pollTimes": {
"item": [
{
"mode": "everyWeek"
}
]
}
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "5f72150b-52c8-4570-9187-ac9bb03dfd99",
"name": "Send Insights Email",
"type": "n8n-nodes-base.gmail",
"position": [
448,
864
],
"parameters": {
"sendTo": "user@example.com",
"message": "=<h2>\ud83d\udcca Negative Sentiment \u2014 Market Intelligence</h2>\n\n<p><strong>Sentiment:</strong> {{ $('Analyze Email Sentiment').item.json.sentimentAnalysis.category }}</p>\n<p><strong>Confidence:</strong> {{ $('Analyze Email Sentiment').item.json.sentimentAnalysis.confidence || 'N/A' }}</p>\n\n<hr>\n\n<h3>Original Email</h3>\n<p><strong>From:</strong> {{ $('Monitor Gmail Inbox').item.json.from }}</p>\n<p><strong>Subject:</strong> {{ $('Monitor Gmail Inbox').item.json.subject }}</p>\n<p><strong>Date:</strong> {{ $('Monitor Gmail Inbox').item.json.date }}</p>\n\n<blockquote>{{ $('Monitor Gmail Inbox').item.json.text }}</blockquote>\n\n<hr>\n\n<p><strong>Recommended Action:</strong> Log this as competitive intelligence. The sender expressed dissatisfaction or disinterest \u2014 review for common objections, pricing concerns, or competitor mentions that can inform event marketing strategy.</p>\n\n<p><em>\u2014 Email Sentiment Router | Braia Labs</em></p>",
"options": {
"appendAttribution": false
},
"subject": "=\ud83d\udcca Market Insight \u2014 {{ $('Monitor Gmail Inbox').item.json.subject }}"
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
},
"typeVersion": 2.1
},
{
"id": "139a8a11-3a78-4778-9afb-d67ad073a0f4",
"name": "Send Follow-up Email",
"type": "n8n-nodes-base.gmail",
"position": [
448,
656
],
"parameters": {
"sendTo": "user@example.com",
"message": "=<h2>\ud83d\udccb Neutral Lead \u2014 Follow-up Required</h2>\n\n<p><strong>Sentiment:</strong> {{ $('Analyze Email Sentiment').item.json.sentimentAnalysis.category }}</p>\n<p><strong>Confidence:</strong> {{ $('Analyze Email Sentiment').item.json.sentimentAnalysis.confidence || 'N/A' }}</p>\n\n<hr>\n\n<h3>Original Email</h3>\n<p><strong>From:</strong> {{ $('Monitor Gmail Inbox').item.json.from }}</p>\n<p><strong>Subject:</strong> {{ $('Monitor Gmail Inbox').item.json.subject }}</p>\n<p><strong>Date:</strong> {{ $('Monitor Gmail Inbox').item.json.date }}</p>\n\n<blockquote>{{ $('Monitor Gmail Inbox').item.json.text }}</blockquote>\n\n<hr>\n\n<p><strong>Recommended Action:</strong> This contact is inquiring about event details but hasn't shown strong commitment. Schedule a nurture follow-up within 24-48 hours with event highlights, speaker lineup, or early-bird offers.</p>\n\n<p><em>\u2014 Email Sentiment Router | Braia Labs</em></p>",
"options": {
"appendAttribution": false
},
"subject": "=\ud83d\udccb Follow-up Needed \u2014 {{ $('Monitor Gmail Inbox').item.json.subject }}"
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
},
"typeVersion": 2.1
},
{
"id": "de774e1a-8a95-45ce-b710-73e6ce65d6ca",
"name": "Fetch Evaluation Dataset Row",
"type": "n8n-nodes-base.evaluationTrigger",
"onError": "continueRegularOutput",
"position": [
-1456,
-128
],
"parameters": {
"dataTableId": {
"__rl": true,
"mode": "id",
"value": "sWTqB6DnzaXG6be6"
}
},
"typeVersion": 4.7
},
{
"id": "cfac0d68-0e0d-4b94-89d7-d794081c14ac",
"name": "Loop Evaluation Batch",
"type": "n8n-nodes-base.splitInBatches",
"position": [
-1200,
-128
],
"parameters": {
"options": {}
},
"typeVersion": 3
},
{
"id": "e12eb17d-58f5-42ec-840d-8004b56ff92a",
"name": "Google Gemini 2.5 Flash Lite",
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"position": [
-880,
464
],
"parameters": {
"options": {},
"modelName": "models/gemini-2.0-flash"
},
"credentials": {
"googlePalmApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "7c31c4bd-8cab-4d2a-b9da-0c0ef7960cd2",
"name": "Record Evaluation Metrics",
"type": "n8n-nodes-base.evaluation",
"position": [
432,
-128
],
"parameters": {
"metric": "categorization",
"options": {},
"operation": "setMetrics",
"actualAnswer": "={{ $json.sentimentAnalysis.category }}",
"expectedAnswer": "={{ $json.expected }}"
},
"typeVersion": 4.8
},
{
"id": "38a96aa9-acd1-4dc8-bc14-a119471863b5",
"name": "Save Evaluation Output",
"type": "n8n-nodes-base.evaluation",
"position": [
192,
-128
],
"parameters": {
"outputs": {
"values": [
{
"outputName": "result",
"outputValue": "={{ $('Analyze Email Sentiment').item.json.sentimentAnalysis.category }}"
}
]
},
"dataTableId": {
"__rl": true,
"mode": "list",
"value": "sWTqB6DnzaXG6be6",
"cachedResultUrl": "/projects/UW9P2Zs3ONybpK7q/datatables/sWTqB6DnzaXG6be6",
"cachedResultName": "Sentiment Analysis Evaluation"
}
},
"typeVersion": 4.8
},
{
"id": "81bfeaa8-40d9-4ca5-bc7f-864101c93b77",
"name": "Gate Neutral Route",
"type": "n8n-nodes-base.evaluation",
"position": [
240,
640
],
"parameters": {
"operation": "checkIfEvaluating"
},
"typeVersion": 4.8
},
{
"id": "6fa8983d-4854-4571-9a59-8280ba9c2f42",
"name": "Gate Positive Route",
"type": "n8n-nodes-base.evaluation",
"position": [
224,
272
],
"parameters": {
"operation": "checkIfEvaluating"
},
"typeVersion": 4.8
},
{
"id": "428de424-67a6-4835-9a8a-e65a20156b91",
"name": "Gate Negative Route",
"type": "n8n-nodes-base.evaluation",
"position": [
240,
848
],
"parameters": {
"operation": "checkIfEvaluating"
},
"typeVersion": 4.8
},
{
"id": "slack-hot-leads-001",
"name": "Post Hot Lead to Slack",
"type": "n8n-nodes-base.slack",
"position": [
432,
464
],
"parameters": {
"text": "=\ud83d\udd25 *Hot Event Lead Detected*\n\n*From:* {{ $('Monitor Gmail Inbox').item.json.from }}\n*Subject:* {{ $('Monitor Gmail Inbox').item.json.subject }}\n*Sentiment:* {{ $('Analyze Email Sentiment').item.json.sentimentAnalysis.category }}\n\n> {{ $('Monitor Gmail Inbox').item.json.text.substring(0, 500) }}{{ $('Monitor Gmail Inbox').item.json.text.length > 500 ? '...' : '' }}\n\n\u26a1 *Action:* Prioritize immediate outreach \u2014 strong buying signals for sponsorship, exhibition, or attendance.",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "name",
"value": "#hot-leads"
},
"otherOptions": {},
"authentication": "oAuth2"
},
"credentials": {
"slackOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 2.3
},
{
"id": "sticky-intro-001",
"name": "Intro \u2014 Overview & Setup",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2144,
64
],
"parameters": {
"width": 600,
"height": 956,
"content": "## Email Sentiment Router for Event Sales Leads\n\n### **What it does:**\nAutomatically analyzes incoming event/conference emails using Google Gemini AI, extracts structured business intelligence (topic, intent, urgency, entities), routes them to the right sales team, and logs everything to an analytics data table.\n\n### **Why it matters:**\nEvent organizers receive hundreds of inbound emails from sponsors, exhibitors, speakers, attendees, and partners. This automation ensures no high-value lead falls through the cracks, every inquiry gets the right response speed, and you build a data-driven picture of your event pipeline over time.\n\n### **How it works:**\n- Gmail Trigger monitors your inbox for new event-related emails\n- Google Gemini #1 analyzes sentiment (Positive / Neutral / Negative)\n- Google Gemini #2 extracts topic, intent, urgency, org, budget signals\n- Every email is logged to the `email_analytics` Data Table + Google Sheets\n- Every email upserts a **Salesforce Lead** (deduped by email) with sentiment + enrichment\n- Hot leads (Positive + urgency >= 7) auto-create **Salesforce Opportunities**\n- Every lead gets a **Salesforce Task** with the AI-suggested follow-up action\n- Google Sheets feeds a **Looker Studio** dashboard for real-time visual analytics\n- Positive \u2192 Hot Lead email + Slack #hot-leads (respond within 2h)\n- Neutral \u2192 Follow-up email + Slack #follow-ups (nurture within 24-48h)\n- Negative \u2192 Insights email + Slack #insights (log for marketing strategy)\n\n### **Setup steps:**\n1. Connect your **Gmail** OAuth2 credential\n2. Connect your **Google Gemini** API credential\n3. Connect your **Slack** OAuth2 credential\n4. Create the `email_analytics` **Data Table** and update the table ID in the Log node\n5. Update recipient email addresses in Send Email nodes (currently placeholders)\n6. Verify Slack channels `#hot-leads`, `#follow-ups`, `#insights` exist\n7. Connect your **Salesforce** OAuth2 credential (Setup > App Manager > New Connected App)\n8. Create 9 custom fields on the Salesforce **Lead** object: `Sentiment__c`, `Sentiment_Confidence__c`, `Primary_Topic__c`, `Lead_Intent__c`, `Urgency_Score__c`, `Budget_Mentioned__c`, `Event_Referenced__c`, `Email_Domain__c`, `Last_Email_Subject__c`\n9. Run the Evaluation Dataset to test accuracy before activating"
},
"typeVersion": 1
},
{
"id": "sticky-trigger-001",
"name": "Section \u2014 Email Trigger",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1504,
64
],
"parameters": {
"color": 6,
"width": 428,
"height": 440,
"content": "## 1. Email Trigger\n\nMonitors Gmail inbox every minute for new incoming event/conference emails. Captures full email metadata including sender, subject, body text, and date."
},
"typeVersion": 1
},
{
"id": "sticky-ai-001",
"name": "Section \u2014 AI Analysis",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1040,
64
],
"parameters": {
"color": 2,
"width": 592,
"height": 536,
"content": "## 2. AI Sentiment & Intelligence Extraction\n\n**Step 1:** Google Gemini classifies email sentiment as **Positive**, **Neutral**, or **Negative** \u2014 tuned for event/conference buying intent.\n\n**Step 2:** A second Gemini call extracts structured intelligence: topic, intent, urgency (1-10), org name, contact, budget signals, and suggested action.\n\n**Step 3:** Switch node re-routes by sentiment category to the Gate nodes."
},
"typeVersion": 1
},
{
"id": "sticky-gate-001",
"name": "Section \u2014 Routing Gate",
"type": "n8n-nodes-base.stickyNote",
"position": [
-416,
64
],
"parameters": {
"color": 4,
"width": 484,
"height": 668,
"content": "## 3. Sentiment Routing Gate\n\nRoutes emails to the correct team based on AI classification. Safety gates prevent accidental emails during evaluation/testing runs."
},
"typeVersion": 1
},
{
"id": "sticky-notify-001",
"name": "Section \u2014 Notifications",
"type": "n8n-nodes-base.stickyNote",
"position": [
96,
64
],
"parameters": {
"color": 5,
"width": 560,
"height": 972,
"content": "## 5. Team Notifications\n\nSends formatted email alerts and Slack channel posts per sentiment route:\n- **Positive** \u2192 Hot Lead Email + `#hot-leads`\n- **Neutral** \u2192 Follow-up Email + `#follow-ups`\n- **Negative** \u2192 Insights Email + `#insights`"
},
"typeVersion": 1
},
{
"id": "sticky-eval-001",
"name": "Section \u2014 Evaluation",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1504,
-304
],
"parameters": {
"color": 7,
"width": 652,
"height": 342,
"content": "## Evaluation Framework (Optional)\n\nTest AI accuracy against a golden dataset before going live. Connect different Gemini models (Flash Lite, Flash, Pro) to compare performance and latency.\n\n**Note:** This section only runs when triggered from the Evaluation Dataset \u2014 it never interferes with production email routing."
},
"typeVersion": 1
},
{
"id": "sticky-metrics-001",
"name": "Section \u2014 Metrics",
"type": "n8n-nodes-base.stickyNote",
"position": [
96,
-256
],
"parameters": {
"color": 7,
"width": 562,
"height": 274,
"content": "## Evaluation Metrics\n\nRecords AI output vs. expected labels and calculates categorization accuracy across the test dataset."
},
"typeVersion": 1
},
{
"id": "ea177aa4-41ff-4f23-9d90-04e90e0629bd",
"name": "Extract Email Intelligence",
"type": "@n8n/n8n-nodes-langchain.informationExtractor",
"position": [
-368,
288
],
"parameters": {
"text": "={{ $json.text || $('Monitor Gmail Inbox').item.json.text || $json.input }}",
"options": {},
"attributes": {
"attributes": [
{
"name": "primary_topic",
"required": true,
"description": "The main topic of this email. Must be exactly one of: sponsorship, exhibition, attendance, speaking, logistics, pricing, registration, partnership, complaint, general"
},
{
"name": "secondary_topics",
"description": "Other topics mentioned in the email, as a comma-separated string. Use same topic values as primary_topic."
},
{
"name": "intent",
"required": true,
"description": "The sender's intent. Must be exactly one of: booking_inquiry, information_request, complaint, cancellation, referral, follow_up, general"
},
{
"name": "urgency_score",
"type": "number",
"required": true,
"description": "Urgency level from 1 (low, just browsing) to 10 (critical, ready to buy/cancel immediately). Consider budget mentions, deadlines, and action language."
},
{
"name": "org_name",
"description": "The sender's organization/company name. Extract from signature, email domain, or body. Empty string if unknown."
},
{
"name": "contact_name",
"description": "The sender's full name. Extract from signature or greeting. Empty string if unknown."
},
{
"name": "budget_mentioned",
"type": "boolean",
"required": true,
"description": "Whether a specific budget, price, or monetary amount is mentioned. true or false."
},
{
"name": "event_referenced",
"description": "The name of the specific event or conference mentioned. Empty string if none."
},
{
"name": "suggested_action",
"required": true,
"description": "A brief one-sentence recommended next action for the sales team. Be specific and actionable."
}
]
}
},
"typeVersion": 1
},
{
"id": "189e277b-9bf7-4a9d-8eb6-f4d26efbc3d3",
"name": "Google Gemini for Enrichment",
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"position": [
-368,
480
],
"parameters": {
"options": {},
"modelName": "models/gemini-2.0-flash"
},
"credentials": {
"googlePalmApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "f8b4b957-efa8-40ed-8607-a66086ddefad",
"name": "Route by Sentiment",
"type": "n8n-nodes-base.switch",
"position": [
-48,
288
],
"parameters": {
"rules": {
"values": [
{
"outputKey": "Positive",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "e02cba87-1ce9-4b70-9be5-0650f861f7b3",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.sentimentAnalysis.category }}",
"rightValue": "Positive"
}
]
},
"renameOutput": true
},
{
"outputKey": "Neutral",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "103002ae-e819-4a83-91b0-bb90f662a4ec",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.sentimentAnalysis.category }}",
"rightValue": "Neutral"
}
]
},
"renameOutput": true
},
{
"outputKey": "Negative",
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "6106e888-ec7a-4a06-b218-e1db0bf13d9e",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.sentimentAnalysis.category }}",
"rightValue": "Negative"
}
]
},
"renameOutput": true
}
]
},
"options": {
"allMatchingOutputs": false
}
},
"typeVersion": 3.2
},
{
"id": "b578e86a-e360-4401-80c3-55500141d6de",
"name": "Prepare Analytics Row",
"type": "n8n-nodes-base.code",
"position": [
-992,
864
],
"parameters": {
"jsCode": "// Prepare analytics row from enriched email data\n// $input comes from Extract Email Intelligence\nconst item = $input.first().json;\n\n// Sentiment data \u2014 try direct property first, then upstream node reference\nlet sentimentCategory = 'Unknown';\nlet sentimentConfidence = 'N/A';\ntry {\n if (item.sentimentAnalysis) {\n sentimentCategory = item.sentimentAnalysis.category || 'Unknown';\n sentimentConfidence = String(item.sentimentAnalysis.confidence || 'N/A');\n } else {\n const sentimentNode = $('Analyze Email Sentiment').first().json;\n sentimentCategory = sentimentNode.sentimentAnalysis?.category || 'Unknown';\n sentimentConfidence = String(sentimentNode.sentimentAnalysis?.confidence || 'N/A');\n }\n} catch (e) {\n // Fallback \u2014 sentiment data not available\n}\n\n// Gmail data \u2014 handle from field as string OR object\nlet fromField = '';\nlet subject = '';\ntry {\n // Try to get from the input item first\n let rawFrom = item.from || null;\n let rawSubject = item.subject || '';\n\n // If not on input, try the Gmail trigger node\n if (!rawFrom) {\n const gmail = $('Monitor Gmail Inbox').first().json;\n rawFrom = gmail.from || '';\n rawSubject = gmail.subject || '';\n }\n\n // Handle from field: could be string \"Name <email>\" or object {name, email}\n if (typeof rawFrom === 'object' && rawFrom !== null) {\n // Object format: {name: \"John Doe\", email: \"user@example.com\"}\n if (rawFrom.email) {\n fromField = rawFrom.name ? `${rawFrom.name} <${rawFrom.email}>` : rawFrom.email;\n } else if (rawFrom.value && Array.isArray(rawFrom.value)) {\n // Some email parsers return {value: [{address: \"...\", name: \"...\"}]}\n const first = rawFrom.value[0];\n fromField = first ? (first.name ? `${first.name} <${first.address}>` : first.address || '') : '';\n } else {\n fromField = JSON.stringify(rawFrom);\n }\n } else {\n fromField = String(rawFrom || '');\n }\n\n subject = String(rawSubject || '');\n} catch (e) {\n // Fallback \u2014 gmail data not available\n}\n\n// Extract domain from email \u2014 fromField is guaranteed to be a string now\nconst domainMatch = fromField.match(/@([^>\\s]+)/);\n\nreturn [{\n json: {\n timestamp: new Date().toISOString(),\n sentiment: sentimentCategory,\n confidence: sentimentConfidence,\n sender_email: fromField,\n sender_domain: domainMatch ? domainMatch[1] : '',\n subject: subject,\n primary_topic: String(item.primary_topic || item.output?.primary_topic || ''),\n secondary_topics: String(item.secondary_topics || item.output?.secondary_topics || ''),\n intent: String(item.intent || item.output?.intent || ''),\n urgency_score: Number(item.urgency_score || item.output?.urgency_score || 0),\n org_name: String(item.org_name || item.output?.org_name || ''),\n contact_name: String(item.contact_name || item.output?.contact_name || ''),\n budget_mentioned: String(item.budget_mentioned ?? item.output?.budget_mentioned ?? false),\n event_referenced: String(item.event_referenced || item.output?.event_referenced || ''),\n suggested_action: String(item.suggested_action || item.output?.suggested_action || ''),\n week_number: getWeekNumber(new Date())\n }\n}];\n\nfunction getWeekNumber(d) {\n const date = new Date(Date.UTC(d.getFullYear(), d.getMonth(), d.getDate()));\n const dayNum = date.getUTCDay() || 7;\n date.setUTCDate(date.getUTCDate() + 4 - dayNum);\n const yearStart = new Date(Date.UTC(date.getUTCFullYear(), 0, 1));\n return Math.ceil((((date - yearStart) / 86400000) + 1) / 7);\n}"
},
"typeVersion": 2,
"continueOnFail": true
},
{
"id": "f8cddd11-178f-4ac8-81a3-5a569596c2f4",
"name": "Log Email Analytics",
"type": "n8n-nodes-base.dataTable",
"position": [
-752,
1056
],
"parameters": {
"columns": {
"value": {},
"mappingMode": "autoMapInputData"
},
"options": {},
"dataTableId": {
"__rl": true,
"mode": "id",
"value": "CVAjTuBbs6dxXjrK"
}
},
"typeVersion": 1,
"continueOnFail": true
},
{
"id": "sticky-analytics-001",
"name": "Section \u2014 Analytics Logging",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1040,
624
],
"parameters": {
"color": 4,
"width": 596,
"height": 580,
"content": "## 4. Analytics Logging\n\nLogs every processed email to:\n- **n8n Data Table** (`email_analytics`) for weekly digests\n- **Google Sheets** for Looker Studio dashboards\n\nBoth run as parallel taps \u2014 never block the main routing flow."
},
"typeVersion": 1
},
{
"id": "f5f89d28-5c40-4274-aca6-a596122fcf96",
"name": "Contact: Braia Labs",
"type": "n8n-nodes-base.stickyNote",
"position": [
704,
64
],
"parameters": {
"width": 540,
"height": 1152,
"content": "## Was this helpful? Get in touch!\n\n I really hope this automation helped you. Your feedback is incredibly valuable and helps me create better resources for business and the n8n community.\n\n### **Have Feedback, a Question, or a Project Idea?**\n\nI've streamlined the way we connect. It all starts with one simple form that takes less than 10 seconds. After that, you'll chat with my AI assistant who will gather the key details and pass them directly on to me.\n\n#### **[Start the conversation here](https://tally.so/r/EkKGgB)** \n\n* **Give Feedback:** Share your thoughts on this template\u2014whether you found a typo, encountered an unexpected error, have a suggestion, or just want to say thanks!\n\n* **n8n Consulting:** Have a complex business challenge or need a custom workflow built from scratch? Let's partner on a powerful automation solution tailored to your specific needs.\n\n* **Join your team:** We can work together to get you launched with confidence. \n\n---\n\nHappy Automating!\n[Milo Bravo](https://linkedin.com/in/MiloBravo/) | BRaiA Labs | Automation & BI Systems + AI Integration"
},
"typeVersion": 1
},
{
"id": "b4b98d8e-b3db-4ee7-80ca-530124934095",
"name": "Append to Google Sheets",
"type": "n8n-nodes-base.googleSheets",
"position": [
-752,
864
],
"parameters": {
"columns": {
"value": {},
"schema": [],
"mappingMode": "autoMapInputData",
"matchingColumns": []
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1eG566RMYjlYc3l2jAy-ilNSrMKbaYvWz7GbJRilsB_o/edit#gid=0",
"cachedResultName": "Analytics"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1eG566RMYjlYc3l2jAy-ilNSrMKbaYvWz7GbJRilsB_o",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1eG566RMYjlYc3l2jAy-ilNSrMKbaYvWz7GbJRilsB_o/edit?usp=drivesdk",
"cachedResultName": "Email Sentiment Analytics"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.5,
"continueOnFail": true
},
{
"id": "210b801f-c964-4217-964c-15b07515a98b",
"name": "Prepare CRM Data",
"type": "n8n-nodes-base.code",
"position": [
-288,
1280
],
"parameters": {
"jsCode": "// Prepare CRM data for Salesforce upsert\nconst item = $input.first().json;\n\n// Extract clean email from \"Name <email>\" format or object\nlet cleanEmail = item.sender_email || '';\nif (typeof cleanEmail === 'object') {\n cleanEmail = cleanEmail.email || cleanEmail.address || JSON.stringify(cleanEmail);\n}\ncleanEmail = String(cleanEmail);\nconst emailMatch = cleanEmail.match(/<([^>]+)>/);\nif (emailMatch) cleanEmail = emailMatch[1];\nelse if (cleanEmail.includes('@')) cleanEmail = cleanEmail.trim();\n\n// Split contact name into first + last\nconst fullName = String(item.contact_name || '').trim();\nconst nameParts = fullName.split(/\\s+/).filter(Boolean);\nconst firstName = nameParts.length > 1 ? nameParts.slice(0, -1).join(' ') : (nameParts[0] || '');\nconst lastName = nameParts.length > 1 ? nameParts[nameParts.length - 1] : (nameParts[0] || 'Unknown');\n\n// Map sentiment to Salesforce Lead Rating\nconst ratingMap = { Positive: 'Hot', Neutral: 'Warm', Negative: 'Cold' };\n\n// Determine if Opportunity should be created (hot leads only)\nconst urgency = Number(item.urgency_score) || 0;\nconst budgetMentioned = item.budget_mentioned === 'true';\nconst createOpportunity = (item.sentiment === 'Positive' && urgency >= 7) || budgetMentioned;\n\nreturn [{\n json: {\n // Standard Lead fields\n email: cleanEmail,\n firstName: firstName,\n lastName: lastName,\n company: String(item.org_name || item.sender_domain || 'Unknown'),\n leadRating: ratingMap[item.sentiment] || 'Warm',\n description: String(item.suggested_action || ''),\n // Custom fields for Salesforce\n sentiment: String(item.sentiment || 'Unknown'),\n sentimentConfidence: String(item.confidence || 'N/A'),\n primaryTopic: String(item.primary_topic || ''),\n leadIntent: String(item.intent || ''),\n urgencyScore: urgency,\n budgetMentioned: budgetMentioned,\n eventReferenced: String(item.event_referenced || ''),\n emailDomain: String(item.sender_domain || ''),\n lastEmailSubject: String(item.subject || ''),\n suggestedAction: String(item.suggested_action || ''),\n // Opportunity control flags\n createOpportunity: createOpportunity,\n opportunityName: createOpportunity\n ? (item.primary_topic || 'Inquiry') + ' \u2014 ' + (item.org_name || cleanEmail) + ' (Week ' + (item.week_number || '') + ')'\n : ''\n }\n}];"
},
"typeVersion": 2,
"continueOnFail": true
},
{
"id": "f91aa4e9-1eb0-44d3-a9ff-598a190c722a",
"name": "Upsert Lead to Salesforce",
"type": "n8n-nodes-base.salesforce",
"position": [
-96,
1280
],
"parameters": {
"company": "={{ $json.company }}",
"lastname": "={{ $json.lastName }}",
"operation": "upsert",
"externalId": "Email",
"externalIdValue": "={{ $json.email }}",
"additionalFields": {
"email": "={{ $json.email }}",
"rating": "={{ $json.leadRating }}",
"description": "={{ $json.description }}",
"customFieldsUi": {
"customFieldsValues": [
{
"value": "={{ $json.sentiment }}",
"fieldId": "Sentiment__c"
},
{
"value": "={{ $json.sentimentConfidence }}",
"fieldId": "Sentiment_Confidence__c"
},
{
"value": "={{ $json.primaryTopic }}",
"fieldId": "Primary_Topic__c"
},
{
"value": "={{ $json.leadIntent }}",
"fieldId": "Lead_Intent__c"
},
{
"value": "={{ $json.urgencyScore }}",
"fieldId": "Urgency_Score__c"
},
{
"value": "={{ $json.budgetMentioned }}",
"fieldId": "Budget_Mentioned__c"
},
{
"value": "={{ $json.eventReferenced }}",
"fieldId": "Event_Referenced__c"
},
{
"value": "={{ $json.emailDomain }}",
"fieldId": "Email_Domain__c"
},
{
"value": "={{ $json.lastEmailSubject }}",
"fieldId": "Last_Email_Subject__c"
}
]
}
}
},
"typeVersion": 1,
"continueOnFail": true
},
{
"id": "8f0e0ca1-efb5-4a9c-bdad-93467e1ad6bc",
"name": "Create Follow-up Task",
"type": "n8n-nodes-base.salesforce",
"position": [
320,
1392
],
"parameters": {
"resource": "task",
"additionalFields": {
"whoId": "={{ $json.id }}",
"priority": "={{ $('Prepare CRM Data').first().json.urgencyScore >= 7 ? 'High' : 'Normal' }}",
"description": "={{ $('Prepare CRM Data').first().json.suggestedAction }}",
"activityDate": "={{ DateTime.now().plus({days: 2}).toISODate() }}"
}
},
"typeVersion": 1,
"continueOnFail": true
},
{
"id": "a8b5505a-f9a3-4849-b127-5f584e146a7f",
"name": "Check Create Opportunity",
"type": "n8n-nodes-base.if",
"position": [
112,
1280
],
"parameters": {
"options": {},
"conditions": {
"options": {
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"operator": {
"type": "boolean",
"operation": "true"
},
"leftValue": "={{ $('Prepare CRM Data').first().json.createOpportunity }}",
"rightValue": true
}
]
}
},
"typeVersion": 2,
"continueOnFail": true
},
{
"id": "3b327e8f-4876-4058-99b8-c1af4846a531",
"name": "Create Opportunity",
"type": "n8n-nodes-base.salesforce",
"position": [
320,
1184
],
"parameters": {
"name": "={{ $('Prepare CRM Data').first().json.opportunityName }}",
"resource": "opportunity",
"closeDate": "={{ DateTime.now().plus({days: 30}).toISODate() }}",
"stageName": "Qualification",
"additionalFields": {
"leadSource": "Email Inquiry",
"description": "={{ $('Prepare CRM Data').first().json.suggestedAction }}"
}
},
"typeVersion": 1,
"continueOnFail": true
},
{
"id": "sticky-crm-001",
"name": "Section \u2014 CRM Integration",
"type": "n8n-nodes-base.stickyNote",
"position": [
-416,
1056
],
"parameters": {
"color": 5,
"width": 1080,
"height": 484,
"content": "## 6. CRM Integration (Salesforce)\n\nEvery processed email automatically syncs to Salesforce:\n- **Upsert Lead** \u2014 deduplicated by email address\n- **Create Task** \u2014 AI-suggested follow-up action\n- **Create Opportunity** \u2014 only for hot leads (Positive sentiment + urgency >= 7 or budget mentioned)\n\nAll CRM nodes use `continueOnFail` \u2014 Salesforce errors never block email routing."
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"callerPolicy": "workflowsFromSameOwner",
"timeSavedMode": "fixed",
"availableInMCP": false,
"executionOrder": "v1",
"saveManualExecutions": true,
"saveExecutionProgress": true,
"saveDataErrorExecution": "all"
},
"versionId": "aead3685-5a9c-420e-a96e-ed3e55927df7",
"connections": {
"Prepare CRM Data": {
"main": [
[
{
"node": "Upsert Lead to Salesforce",
"type": "main",
"index": 0
}
]
]
},
"Gate Neutral Route": {
"main": [
[
{
"node": "Save Evaluation Output",
"type": "main",
"index": 0
}
],
[
{
"node": "Send Follow-up Email",
"type": "main",
"index": 0
}
]
]
},
"Route by Sentiment": {
"main": [
[
{
"node": "Gate Positive Route",
"type": "main",
"index": 0
}
],
[
{
"node": "Gate Neutral Route",
"type": "main",
"index": 0
}
],
[
{
"node": "Gate Negative Route",
"type": "main",
"index": 0
}
]
]
},
"Gate Negative Route": {
"main": [
[
{
"node": "Save Evaluation Output",
"type": "main",
"index": 0
}
],
[
{
"node": "Send Insights Email",
"type": "main",
"index": 0
}
]
]
},
"Gate Positive Route": {
"main": [
[
{
"node": "Save Evaluation Output",
"type": "main",
"index": 0
}
],
[
{
"node": "Send Hot Lead Email",
"type": "main",
"index": 0
},
{
"node": "Post Hot Lead to Slack",
"type": "main",
"index": 0
}
]
]
},
"Monitor Gmail Inbox": {
"main": [
[
{
"node": "Analyze Email Sentiment",
"type": "main",
"index": 0
}
]
]
},
"Loop Evaluation Batch": {
"main": [
[],
[
{
"node": "Analyze Email Sentiment",
"type": "main",
"index": 0
}
]
]
},
"Prepare Analytics Row": {
"main": [
[
{
"node": "Log Email Analytics",
"type": "main",
"index": 0
},
{
"node": "Append to Google Sheets",
"type": "main",
"index": 0
},
{
"node": "Prepare CRM Data",
"type": "main",
"index": 0
}
]
]
},
"Save Evaluation Output": {
"main": [
[
{
"node": "Record Evaluation Metrics",
"type": "main",
"index": 0
}
]
]
},
"Analyze Email Sentiment": {
"main": [
[
{
"node": "Route by Sentiment",
"type": "main",
"index": 0
},
{
"node": "Extract Email Intelligence",
"type": "main",
"index": 0
}
],
[
{
"node": "Route by Sentiment",
"type": "main",
"index": 0
},
{
"node": "Extract Email Intelligence",
"type": "main",
"index": 0
}
],
[
{
"node": "Route by Sentiment",
"type": "main",
"index": 0
},
{
"node": "Extract Email Intelligence",
"type": "main",
"index": 0
}
]
]
},
"Check Create Opportunity": {
"main": [
[
{
"node": "Create Opportunity",
"type": "main",
"index": 0
}
],
[]
]
},
"Record Evaluation Metrics": {
"main": [
[
{
"node": "Loop Evaluation Batch",
"type": "main",
"index": 0
}
]
]
},
"Upsert Lead to Salesforce": {
"main": [
[
{
"node": "Check Create Opportunity",
"type": "main",
"index": 0
},
{
"node": "Create Follow-up Task",
"type": "main",
"index": 0
}
]
]
},
"Extract Email Intelligence": {
"main": [
[
{
"node": "Prepare Analytics Row",
"type": "main",
"index": 0
}
]
]
},
"Fetch Evaluation Dataset Row": {
"main": [
[
{
"node": "Loop Evaluation Batch",
"type": "main",
"index": 0
}
]
]
},
"Google Gemini 2.5 Flash Lite": {
"ai_languageModel": [
[
{
"node": "Analyze Email Sentiment",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Google Gemini for Enrichment": {
"ai_languageModel": [
[
{
"node": "Extract Email Intelligence",
"type": "ai_languageModel",
"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.
gmailOAuth2googlePalmApigoogleSheetsOAuth2ApislackOAuth2Api
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Who is this for? Event sales teams & conference organizers processing 100+ sponsor/partner emails weekly who need instant lead qualification, Salesforce automation, & pipeline analytics. _
Source: https://n8n.io/workflows/13740/ — 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.
Email Sentiment Router for Event Sales Leads
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 Googl
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
Stop wasting time on bad leads and manual research. This advanced n8n workflow automates your entire lead qualification and CRM entry process for HubSpot, ensuring you only sync high-quality, pre-rese
SMB sales teams and SaaS companies who want to automatically prioritize and nurture new leads without manual qualification. Perfect for businesses getting 50+ leads per month who need to identify high