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 -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.
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:
This n8n template helps Magento 2 merchants automatically send customised, beautifully branded coupon emails to high-value customers.