This workflow follows the Emailreadimap → HTTP Request 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 →
{
"name": "04 - Reply Detection & Follow-up",
"nodes": [
{
"parameters": {
"rule": {
"interval": [
{
"field": "hours",
"hoursInterval": 2
}
]
}
},
"id": "reply-trigger",
"name": "Check Every 2 Hours",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.2,
"position": [
240,
300
]
},
{
"id": "imap-trigger-node",
"name": "Fetch Unread Email (IMAP)",
"type": "n8n-nodes-base.emailReadImap",
"typeVersion": 2,
"position": [
460,
300
],
"parameters": {
"mailbox": "INBOX",
"action": "read",
"markSeen": true,
"download": false,
"options": {}
},
"credentials": {
"imap": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"jsCode": "// Filter replies from target emails in outreach_log\nconst emails = $input.all();\nconst replies = emails.filter(item => {\n const from = item.json.from || '';\n const subject = (item.json.subject || '').toLowerCase();\n const body = (item.json.text || item.json.snippet || '').toLowerCase();\n \n // Exclude auto-replies\n const isAutoReply = [\n 'out of office', 'auto-reply', 'automatic reply',\n 'vacation', 'away from', 'noreply',\n ].some(kw => subject.includes(kw) || body.includes(kw));\n \n if (isAutoReply) return false;\n \n // Detect positive reply intent\n const positiveSignals = [\n 'interested', 'yes', 'sure', 'please', 'tell me more',\n 'call', 'meeting', 'schedule', 'demo', 'price', 'cost',\n 'how much', 'magkano', 'tara', 'ok', 'pwede',\n ];\n const hasPositive = positiveSignals.some(kw => body.includes(kw));\n return true; // Return all unread emails, classify in next node\n});\n\nconsole.log(`Emails to process: ${replies.length}`);\nreturn replies.slice(0, 20);"
},
"id": "filter-replies",
"name": "Filter & Parse Replies",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
680,
300
]
},
{
"parameters": {
"model": "gemini-2.0-flash",
"messages": {
"values": [
{
"role": "user",
"content": "Classify this email reply from a Philippine business:\n\nFrom: {{ $json.from }}\nSubject: {{ $json.subject }}\nBody: {{ $json.text || $json.snippet }}\n\nReturn JSON only:\n{\"intent\": \"interested|not_interested|auto_reply|unsubscribe|other\", \"sentiment\": \"positive|neutral|negative\", \"suggested_action\": \"schedule_call|send_followup|remove_from_list|no_action\", \"urgency\": \"high|medium|low\", \"summary\": \"one line summary\"}"
}
]
},
"options": {
"temperature": 0.1
}
},
"id": "classify-intent",
"name": "Classify Intent (Gemini)",
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"typeVersion": 1,
"position": [
900,
300
],
"credentials": {
"googlePalmApi": {
"name": "<your credential>"
}
}
},
{
"parameters": {
"jsCode": "const email = $('Filter & Parse Replies').item.json;\nconst rawReply = $input.item.json.text || $input.item.json.response || '{}';\n\nlet classification = {};\ntry {\n const jsonStart = rawReply.indexOf('{');\n const jsonEnd = rawReply.lastIndexOf('}') + 1;\n if (jsonStart >= 0) classification = JSON.parse(rawReply.slice(jsonStart, jsonEnd));\n} catch(e) {\n classification = { intent: 'other', sentiment: 'neutral', suggested_action: 'no_action' };\n}\n\nreturn [{\n json: {\n email_id: email.uid || email.id || \"unknown\",\n from: email.from,\n subject: email.subject,\n intent: classification.intent,\n sentiment: classification.sentiment,\n suggested_action: classification.suggested_action,\n urgency: classification.urgency,\n summary: classification.summary,\n timestamp: new Date().toISOString(),\n }\n}];"
},
"id": "parse-classification",
"name": "Parse Classification",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1120,
300
]
},
{
"parameters": {
"conditions": {
"options": {
"caseSensitive": false
},
"conditions": [
{
"leftValue": "={{ $json.intent }}",
"rightValue": "interested",
"operator": {
"type": "string",
"operation": "equals"
}
}
]
}
},
"id": "route-intent",
"name": "Is Interested?",
"type": "n8n-nodes-base.if",
"typeVersion": 2,
"position": [
1340,
300
]
},
{
"parameters": {
"method": "POST",
"url": "http://sales-outreach:8080/webhook/hot-lead",
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "from",
"value": "={{ $json.from }}"
},
{
"name": "subject",
"value": "={{ $json.subject }}"
},
{
"name": "intent",
"value": "={{ $json.intent }}"
},
{
"name": "urgency",
"value": "={{ $json.urgency }}"
},
{
"name": "suggested_action",
"value": "={{ $json.suggested_action }}"
},
{
"name": "summary",
"value": "={{ $json.summary }}"
}
]
}
},
"id": "alert-hot-lead",
"name": "Alert: Hot Lead!",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1560,
220
],
"notes": "Replace with Telegram Bot or Slack for urgent notification push"
},
{
"parameters": {
"method": "POST",
"url": "http://lead-miner:8000/leads/update-status",
"sendBody": true,
"bodyParameters": {
"parameters": [
{
"name": "email",
"value": "={{ $('Parse Classification').item.json.from }}"
},
{
"name": "status",
"value": "={{ $('Parse Classification').item.json.intent }}"
}
]
}
},
"id": "update-outreach-log",
"name": "Update outreach_log",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1560,
560
],
"continueOnFail": true,
"notes": "Update outreach_log.status field to record reply status"
}
],
"connections": {
"Check Every 2 Hours": {
"main": [
[
{
"node": "Fetch Unread Email (IMAP)",
"type": "main",
"index": 0
}
]
]
},
"Filter & Parse Replies": {
"main": [
[
{
"node": "Classify Intent (Gemini)",
"type": "main",
"index": 0
}
]
]
},
"Classify Intent (Gemini)": {
"main": [
[
{
"node": "Parse Classification",
"type": "main",
"index": 0
}
]
]
},
"Parse Classification": {
"main": [
[
{
"node": "Is Interested?",
"type": "main",
"index": 0
}
]
]
},
"Is Interested?": {
"main": [
[
{
"node": "Alert: Hot Lead!",
"type": "main",
"index": 0
}
],
[
{
"node": "Update outreach_log",
"type": "main",
"index": 0
}
]
]
},
"Alert: Hot Lead!": {
"main": [
[
{
"node": "Update outreach_log",
"type": "main",
"index": 0
}
]
]
},
"Fetch Unread Email (IMAP)": {
"main": [
[
{
"node": "Filter & Parse Replies",
"type": "main",
"index": 0
}
]
]
}
},
"active": false,
"settings": {
"executionOrder": "v1",
"saveExecutionProgress": true
},
"tags": [],
"meta": {
"description": "Check unread emails every 2 hours \u2014 use Gemini to classify reply intent, push alerts for hot leads immediately"
},
"id": "357b1ca7-4294-4f04-81ad-63200eb64b7f"
}
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.
googlePalmApiimap
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
04 - Reply Detection & Follow-up. Uses emailReadImap, lmChatGoogleGemini, httpRequest. Scheduled trigger; 8 nodes.
Source: https://github.com/kaneliu120/lead-mining-system/blob/9197dfc0289d444b23dc2d461544adc8380bffb8/n8n-workflows/04-reply-detection.json — 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.
One of my top workflow requests, this template can save many hours of manual labour for you or your finance/accounts team. A scheduled trigger is set to fetch recent Outlook messages to the Accounts r
3396. Uses microsoftOutlook, textClassifier, lmChatGoogleGemini, microsoftExcel. Scheduled trigger; 24 nodes.
WF02: pSEO記事投稿. Uses googleSheets, lmChatGoogleGemini, httpRequest. Scheduled trigger; 10 nodes.
AI Institutional Stock Valuation Engine with Risk Scoring & Scenario Targets
Overview This is a production-grade, fully automated stock analysis system built entirely in n8n. It combines institutional-level financial analysis, dual AI model consensus, and a self-improving back