This workflow follows the Gmail → 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": "AI Email Agent - Self Learning",
"nodes": [
{
"id": "schedule",
"name": "Every 5 min",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.2,
"position": [
-400,
300
],
"parameters": {
"rule": {
"interval": [
{
"field": "minutes",
"minutesInterval": 5
}
]
}
}
},
{
"id": "manual",
"name": "Manual Test",
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [
-400,
450
],
"parameters": {}
},
{
"id": "get-emails",
"name": "Get Unread Emails",
"type": "n8n-nodes-base.gmail",
"typeVersion": 2.1,
"position": [
-150,
375
],
"parameters": {
"operation": "getAll",
"limit": 3,
"filters": {
"q": "is:unread -in:spam -in:trash -category:promotions -category:social -category:updates"
}
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
}
},
{
"id": "has-emails",
"name": "Has Emails?",
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
80,
375
],
"parameters": {
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"conditions": [
{
"id": "check-id",
"leftValue": "={{ $json.id }}",
"rightValue": "",
"operator": {
"type": "string",
"operation": "exists"
}
}
],
"combinator": "and"
}
}
},
{
"id": "prepare-text",
"name": "Prepare Email Text",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
300,
300
],
"parameters": {
"jsCode": "// Prepare email text for embedding\nconst email = $input.first().json;\n\n// Combine subject and snippet for embedding\nconst emailText = `Subject: ${email.Subject || email.subject || 'No Subject'}\\nFrom: ${email.From || email.from || 'Unknown'}\\nContent: ${email.snippet || ''}`;\n\n// Create unique ID for this email\nconst emailId = email.id || email.messageId;\n\nreturn [{\n json: {\n emailId: emailId,\n threadId: email.threadId,\n from: email.From || email.from,\n subject: email.Subject || email.subject,\n snippet: email.snippet,\n textForEmbedding: emailText,\n labels: email.labels || [],\n receivedAt: new Date().toISOString()\n }\n}];"
}
},
{
"id": "get-embedding",
"name": "Get Embedding (Gemini)",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
530,
300
],
"parameters": {
"method": "POST",
"url": "https://generativelanguage.googleapis.com/v1beta/models/text-embedding-004:embedContent",
"sendQuery": true,
"queryParameters": {
"parameters": [
{
"name": "key",
"value": "YOUR_GEMINI_API_KEY"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ JSON.stringify({ content: { parts: [{ text: $json.textForEmbedding }] } }) }}",
"options": {
"response": {
"response": {
"responseFormat": "json"
}
}
}
}
},
{
"id": "search-similar",
"name": "Search Similar (Qdrant)",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
760,
300
],
"parameters": {
"method": "POST",
"url": "https://YOUR_QDRANT_CLUSTER.cloud.qdrant.io:6333/collections/email_memory/points/search",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "api-key",
"value": "YOUR_QDRANT_API_KEY"
},
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ JSON.stringify({ vector: $json.embedding.values, limit: 3, with_payload: true }) }}",
"options": {
"response": {
"response": {
"responseFormat": "json"
}
}
}
}
},
{
"id": "store-memory",
"name": "Store in Memory (Qdrant)",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
990,
300
],
"parameters": {
"method": "PUT",
"url": "https://YOUR_QDRANT_CLUSTER.cloud.qdrant.io:6333/collections/email_memory/points",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "api-key",
"value": "YOUR_QDRANT_API_KEY"
},
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ (() => { const prevData = $('Prepare Email Text').first().json; const embedding = $('Get Embedding (Gemini)').first().json.embedding.values; const pointId = Date.now(); return JSON.stringify({ points: [{ id: pointId, vector: embedding, payload: { emailId: prevData.emailId, from: prevData.from, subject: prevData.subject, snippet: prevData.snippet, receivedAt: prevData.receivedAt } }] }); })() }}",
"options": {
"response": {
"response": {
"responseFormat": "json"
}
}
}
}
},
{
"id": "ai-analysis",
"name": "AI Analysis (Groq)",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.2,
"position": [
1220,
300
],
"parameters": {
"method": "POST",
"url": "https://api.groq.com/openai/v1/chat/completions",
"sendHeaders": true,
"headerParameters": {
"parameters": [
{
"name": "Authorization",
"value": "Bearer YOUR_GROQ_API_KEY"
},
{
"name": "Content-Type",
"value": "application/json"
}
]
},
"sendBody": true,
"specifyBody": "json",
"jsonBody": "={{ (() => { const emailData = $('Prepare Email Text').first().json; const similarEmails = $('Search Similar (Qdrant)').first().json.result || []; const similarContext = similarEmails.map(e => `- ${e.payload?.subject || 'No subject'}: ${e.payload?.snippet || ''}`).join('\\n'); const prompt = `You are an intelligent email assistant. Analyze this email and decide how to handle it.\\n\\nCURRENT EMAIL:\\nFrom: ${emailData.from}\\nSubject: ${emailData.subject}\\nContent: ${emailData.snippet}\\n\\nSIMILAR PAST EMAILS FROM MEMORY:\\n${similarContext || 'No similar emails found yet.'}\\n\\nBased on the email and any patterns from similar emails, provide:\\n1. PRIORITY: high, medium, or low\\n2. CATEGORY: work, personal, notification, newsletter, spam, important\\n3. ACTION: star, archive, reply_needed, ignore\\n4. REASON: Brief explanation (1 sentence)\\n\\nRespond ONLY in this JSON format:\\n{\"priority\": \"...\", \"category\": \"...\", \"action\": \"...\", \"reason\": \"...\"}`; return JSON.stringify({ model: 'llama-3.3-70b-versatile', messages: [{ role: 'user', content: prompt }], temperature: 0.3, max_tokens: 200 }); })() }}",
"options": {
"response": {
"response": {
"responseFormat": "json"
}
}
}
}
},
{
"id": "process-ai",
"name": "Process AI Response",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1450,
300
],
"parameters": {
"jsCode": "// Process AI response and prepare actions\nconst emailData = $('Prepare Email Text').first().json;\nconst aiResponse = $input.first().json;\n\nlet decision = {\n priority: 'medium',\n category: 'unknown',\n action: 'ignore',\n reason: 'Could not parse AI response'\n};\n\ntry {\n const content = aiResponse.choices[0].message.content;\n const jsonMatch = content.match(/\\{[\\s\\S]*\\}/);\n if (jsonMatch) {\n decision = JSON.parse(jsonMatch[0]);\n }\n} catch (e) {\n console.log('Parse error:', e.message);\n}\n\nreturn [{\n json: {\n emailId: emailData.emailId,\n threadId: emailData.threadId,\n from: emailData.from,\n subject: emailData.subject,\n ai_priority: decision.priority,\n ai_category: decision.category,\n ai_action: decision.action,\n ai_reason: decision.reason,\n shouldStar: decision.action === 'star' || decision.priority === 'high',\n processed_at: new Date().toISOString()\n }\n}];"
}
},
{
"id": "should-star",
"name": "Should Star?",
"type": "n8n-nodes-base.if",
"typeVersion": 2.2,
"position": [
1680,
300
],
"parameters": {
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"conditions": [
{
"id": "check-star",
"leftValue": "={{ $json.shouldStar }}",
"rightValue": true,
"operator": {
"type": "boolean",
"operation": "equals"
}
}
],
"combinator": "and"
}
}
},
{
"id": "star-email",
"name": "Star Important",
"type": "n8n-nodes-base.gmail",
"typeVersion": 2.1,
"position": [
1910,
225
],
"parameters": {
"operation": "addLabels",
"messageId": "={{ $json.emailId }}",
"labelIds": [
"STARRED"
]
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
}
},
{
"id": "done",
"name": "Done",
"type": "n8n-nodes-base.noOp",
"typeVersion": 1,
"position": [
2140,
300
],
"parameters": {}
},
{
"id": "no-emails",
"name": "No Emails",
"type": "n8n-nodes-base.noOp",
"typeVersion": 1,
"position": [
300,
450
],
"parameters": {}
}
],
"connections": {
"Every 5 min": {
"main": [
[
{
"node": "Get Unread Emails",
"type": "main",
"index": 0
}
]
]
},
"Manual Test": {
"main": [
[
{
"node": "Get Unread Emails",
"type": "main",
"index": 0
}
]
]
},
"Get Unread Emails": {
"main": [
[
{
"node": "Has Emails?",
"type": "main",
"index": 0
}
]
]
},
"Has Emails?": {
"main": [
[
{
"node": "Prepare Email Text",
"type": "main",
"index": 0
}
],
[
{
"node": "No Emails",
"type": "main",
"index": 0
}
]
]
},
"Prepare Email Text": {
"main": [
[
{
"node": "Get Embedding (Gemini)",
"type": "main",
"index": 0
}
]
]
},
"Get Embedding (Gemini)": {
"main": [
[
{
"node": "Search Similar (Qdrant)",
"type": "main",
"index": 0
}
]
]
},
"Search Similar (Qdrant)": {
"main": [
[
{
"node": "Store in Memory (Qdrant)",
"type": "main",
"index": 0
}
]
]
},
"Store in Memory (Qdrant)": {
"main": [
[
{
"node": "AI Analysis (Groq)",
"type": "main",
"index": 0
}
]
]
},
"AI Analysis (Groq)": {
"main": [
[
{
"node": "Process AI Response",
"type": "main",
"index": 0
}
]
]
},
"Process AI Response": {
"main": [
[
{
"node": "Should Star?",
"type": "main",
"index": 0
}
]
]
},
"Should Star?": {
"main": [
[
{
"node": "Star Important",
"type": "main",
"index": 0
}
],
[
{
"node": "Done",
"type": "main",
"index": 0
}
]
]
},
"Star Important": {
"main": [
[
{
"node": "Done",
"type": "main",
"index": 0
}
]
]
}
},
"settings": {
"executionOrder": "v1",
"saveDataErrorExecution": "all",
"saveDataSuccessExecution": "all",
"saveManualExecutions": true
}
}
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.
gmailOAuth2
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
AI Email Agent - Self Learning. Uses gmail, httpRequest. Scheduled trigger; 14 nodes.
Source: https://gist.github.com/przemo198004-hue/eb73403ddc73e25bbd58abda428f0d9f — 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.
Template 14310. Uses httpRequest, stopAndError, slack, gmail. Scheduled trigger; 53 nodes.
This automation includes order analysis, product comparison, management approval, and automated product deactivation, with full reporting and transparency. 1st of Every Month at 8 AM, it triggers a sc
BSW Growth Agent · Lite (Free Tier). Uses googleSheets, googleDrive, httpRequest, gmail. Scheduled trigger; 21 nodes.
Founder's Discovery Engine. Uses googleSheets, googleDrive, httpRequest, gmail. Scheduled trigger; 21 nodes.
It identifies SKUs with low inventory per source and sends daily alerts via: