基于AI的邮件分诊:从Gmail到Slack和Sheets
高级
这是一个自动化工作流,包含 34 个节点。主要使用 If, Code, Slack, GmailTrigger, GoogleSheets 等节点。 集成Gmail、GPT-4、Slack和Google Sheets的智能邮件分诊
前置要求
- •Slack Bot Token 或 Webhook URL
- •Google 账号和 Gmail API 凭证
- •Google Sheets API 凭证
- •OpenAI API Key
使用的节点 (34)
分类
-
工作流预览
可视化展示节点连接关系,支持缩放和平移
导出工作流
复制以下 JSON 配置到 n8n 导入,即可使用此工作流
{
"id": "EkrH16IadUZrhHQT",
"meta": {
"instanceId": "8443f10082278c46aa5cf3acf8ff0f70061a2c58bce76efac814b16290845177",
"templateCredsSetupCompleted": true
},
"name": "AI-Powered Email Triage from Gmail to Slack and Sheets",
"tags": [],
"nodes": [
{
"id": "0165f79d-f529-425c-8b1c-acdb665c4e04",
"name": "Gmail Trigger",
"type": "n8n-nodes-base.gmailTrigger",
"position": [
-1696,
608
],
"parameters": {
"simple": false,
"filters": {},
"options": {},
"pollTimes": {
"item": [
{
"mode": "everyMinute"
}
]
}
},
"credentials": {
"gmailOAuth2": {
"id": "gEIaWCTvGfYjMSb3",
"name": "Gmail credentials"
}
},
"typeVersion": 1
},
{
"id": "ad5d0c60-0851-4084-89b8-29f93541cba9",
"name": "Extract Email Data",
"type": "n8n-nodes-base.code",
"position": [
-1472,
608
],
"parameters": {
"jsCode": "const emailData = items[0].json;\n\nconst extractedData = {\n sender: emailData.from || 'Unknown Sender',\n subject: emailData.subject || 'No Subject',\n bodyText: emailData.textPlain || emailData.text || '',\n bodyHtml: emailData.html || '',\n attachments: emailData.attachments || [],\n messageId: emailData.id,\n receivedDate: emailData.date || new Date().toISOString(),\n threadId: emailData.threadId\n};\n\nconst linkRegex = /https?:\\/\\/[^\\s<>\"{}|\\\\^`\\[\\]]+/gi;\nconst textLinks = (extractedData.bodyText.match(linkRegex) || []);\nconst htmlLinks = (extractedData.bodyHtml.match(linkRegex) || []);\nconst allLinks = [...new Set([...textLinks, ...htmlLinks])];\n\nextractedData.links = allLinks;\n\n// ENHANCED ATTACHMENT DETECTION LOGIC\nlet attachmentCount = 0;\nlet hasAttachments = false;\n\n// Check the original attachments array first\nif (extractedData.attachments && extractedData.attachments.length > 0) {\n attachmentCount = extractedData.attachments.length;\n hasAttachments = true;\n}\n\n// Check Gmail payload parts for attachments\nif (!hasAttachments && emailData.payload && emailData.payload.parts) {\n const attachmentParts = emailData.payload.parts.filter(part => \n part.filename && part.filename !== '' && part.body && part.body.attachmentId\n );\n if (attachmentParts.length > 0) {\n attachmentCount = attachmentParts.length;\n hasAttachments = true;\n }\n}\n\n// Check content-type header for multipart/mixed (indicates attachments)\nif (!hasAttachments && emailData.headers && emailData.headers['content-type']) {\n const contentType = emailData.headers['content-type'];\n if (contentType.includes('multipart/mixed')) {\n hasAttachments = true;\n attachmentCount = 1; // At least one attachment\n }\n}\n\n// Check email content for attachment keywords as final fallback\nif (!hasAttachments) {\n const emailText = (extractedData.bodyText + ' ' + extractedData.bodyHtml).toLowerCase();\n const attachmentKeywords = ['attached', 'attachment', 'please review the attached', 'pdf', 'excel', 'document'];\n \n if (attachmentKeywords.some(keyword => emailText.includes(keyword))) {\n hasAttachments = true;\n attachmentCount = 1;\n }\n}\n\nextractedData.hasAttachments = hasAttachments;\nextractedData.attachmentCount = attachmentCount;\n\nconst bodyForAnalysis = extractedData.bodyText || extractedData.bodyHtml.replace(/<[^>]*>/g, ' ').replace(/\\s+/g, ' ').trim();\nextractedData.bodyForAnalysis = bodyForAnalysis.substring(0, 3000);\n\nreturn [{ json: extractedData }];"
},
"typeVersion": 2
},
{
"id": "0a775b80-163e-4048-8fd3-01ab020a3d2a",
"name": "Check Attachments",
"type": "n8n-nodes-base.if",
"position": [
-1248,
608
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 1,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "or",
"conditions": [
{
"id": "has-attachments",
"operator": {
"type": "boolean",
"operation": "equal"
},
"leftValue": "={{ $json.hasAttachments }}",
"rightValue": true
},
{
"id": "bdea6274-0c71-4d15-b97d-8cd325208efe",
"operator": {
"type": "boolean",
"operation": "true",
"singleValue": true
},
"leftValue": "={{ $json.hasAttachments }}",
"rightValue": 0
}
]
}
},
"typeVersion": 2
},
{
"id": "60bdd6dc-2c09-4e41-bd24-2d191827cfde",
"name": "Process Attachments",
"type": "n8n-nodes-base.code",
"position": [
-1024,
512
],
"parameters": {
"jsCode": "const emailData = items[0].json;\nlet attachmentText = '';\nconst processedAttachments = [];\n\nif (emailData.attachments && emailData.attachments.length > 0) {\n for (const attachment of emailData.attachments) {\n const processed = {\n filename: attachment.filename || 'unknown',\n contentType: attachment.contentType || 'unknown',\n size: attachment.size || 0,\n textExtracted: false,\n extractedText: ''\n };\n \n if (attachment.contentType) {\n if (attachment.contentType.includes('text/')) {\n processed.extractedText = 'Text file content available';\n processed.textExtracted = true;\n } else if (attachment.contentType.includes('pdf')) {\n processed.extractedText = 'PDF attachment detected - text extraction requires additional service';\n processed.textExtracted = false;\n } else if (attachment.contentType.includes('word') || attachment.contentType.includes('document')) {\n processed.extractedText = 'Word document detected - text extraction requires additional service';\n processed.textExtracted = false;\n }\n }\n \n processedAttachments.push(processed);\n \n if (processed.textExtracted) {\n attachmentText += `\\n[Attachment: ${processed.filename}] ${processed.extractedText}`;\n }\n }\n}\n\nconst combinedContent = emailData.bodyForAnalysis + attachmentText;\n\nreturn [{\n json: {\n ...emailData,\n processedAttachments,\n combinedContent: combinedContent.substring(0, 4000),\n attachmentProcessingComplete: true\n }\n}];"
},
"typeVersion": 2
},
{
"id": "cabfad79-67be-4fb5-83ca-a22b73275101",
"name": "Skip Attachments",
"type": "n8n-nodes-base.code",
"position": [
-1024,
704
],
"parameters": {
"jsCode": "const emailData = items[0].json;\n\nreturn [{\n json: {\n ...emailData,\n processedAttachments: [],\n combinedContent: emailData.bodyForAnalysis,\n attachmentProcessingComplete: true\n }\n}];"
},
"typeVersion": 2
},
{
"id": "8a4771ff-2e1f-4411-9b7f-7c57b663494e",
"name": "Parse AI Response",
"type": "n8n-nodes-base.code",
"position": [
-336,
608
],
"parameters": {
"jsCode": "// Parse AI response and handle the actual output structure\nlet aiData;\ntry {\n // Get the AI response - handle multiple possible structures\n let aiResponse;\n \n // Check if it's the direct output structure you showed\n if (items[0].json.output) {\n aiResponse = items[0].json.output;\n }\n // Check for standard OpenAI response formats\n else if (items[0].json.message?.content) {\n const content = items[0].json.message.content;\n // Try to parse JSON from content\n const jsonMatch = content.match(/\\{[\\s\\S]*\\}/);\n if (jsonMatch) {\n aiResponse = JSON.parse(jsonMatch[0]);\n } else {\n aiResponse = content;\n }\n }\n // Check for other possible response formats\n else if (items[0].json.text) {\n const text = items[0].json.text;\n const jsonMatch = text.match(/\\{[\\s\\S]*\\}/);\n if (jsonMatch) {\n aiResponse = JSON.parse(jsonMatch[0]);\n } else {\n aiResponse = text;\n }\n }\n // Check if the response is directly in the json\n else if (items[0].json.summary || items[0].json.callToAction || items[0].json.insights) {\n aiResponse = items[0].json;\n }\n else {\n throw new Error('Unknown AI response format');\n }\n \n // Now handle the parsed response\n if (typeof aiResponse === 'object' && aiResponse.summary) {\n // Direct object format (like your output)\n aiData = {\n summary: aiResponse.summary || 'AI analysis unavailable',\n callToAction: aiResponse.callToAction || 'For Your Information',\n insights: aiResponse.insights || 'No specific insights available'\n };\n } else if (typeof aiResponse === 'string') {\n // String format - try to parse JSON\n const jsonMatch = aiResponse.match(/\\{[\\s\\S]*\\}/);\n if (jsonMatch) {\n const parsed = JSON.parse(jsonMatch[0]);\n aiData = {\n summary: parsed.summary || 'AI analysis unavailable',\n callToAction: parsed.callToAction || 'For Your Information',\n insights: parsed.insights || 'No specific insights available'\n };\n } else {\n throw new Error('Could not extract JSON from AI response');\n }\n } else {\n throw new Error('Unexpected AI response format');\n }\n \n // Validate and clean up the data\n if (!aiData.summary) aiData.summary = 'AI analysis unavailable';\n if (!aiData.callToAction) aiData.callToAction = 'For Your Information';\n if (!aiData.insights) aiData.insights = 'No specific insights available';\n \n // Ensure callToAction is one of the expected values\n const validActions = ['Reply Needed', 'Review Attachment', 'For Your Information'];\n if (!validActions.includes(aiData.callToAction)) {\n aiData.callToAction = 'For Your Information';\n }\n \n} catch (error) {\n // Fallback if AI parsing fails\n aiData = {\n summary: 'Email received but AI analysis failed. Please review manually.',\n callToAction: 'For Your Information',\n insights: 'Manual review required due to AI processing error.',\n aiError: true,\n aiErrorMessage: error.message\n };\n}\n\n// Get the original email data from the previous node\n// Try multiple node references in case the node name is different\nlet emailData;\ntry {\n emailData = $node['AI Analysis'].json || $input.first().json;\n} catch (e) {\n // Fallback to items[0].json if node reference fails\n emailData = items[0].json;\n}\n\n// Return the processed data\nreturn [{\n json: {\n ...emailData,\n aiAnalysis: aiData,\n processingComplete: true,\n timestamp: new Date().toISOString()\n }\n}];"
},
"typeVersion": 2
},
{
"id": "e654bdf6-3782-4220-ade3-19bf09294e2a",
"name": "Route Urgent",
"type": "n8n-nodes-base.if",
"position": [
-112,
608
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 1,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "reply-needed",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.aiAnalysis.callToAction }}",
"rightValue": "Reply Needed"
}
]
}
},
"typeVersion": 2
},
{
"id": "1a1f32a6-67f2-4bb4-92b1-3c0e6b6c40ee",
"name": "Route Attachments",
"type": "n8n-nodes-base.if",
"position": [
112,
704
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 1,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "review-attachment",
"operator": {
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.aiAnalysis.callToAction }}",
"rightValue": "Review Attachment"
}
]
}
},
"typeVersion": 2
},
{
"id": "7f338c68-740c-48b0-9776-c57bd4707d60",
"name": "Slack Urgent",
"type": "n8n-nodes-base.slack",
"position": [
336,
416
],
"webhookId": "4e77062d-a1d4-46ca-8d70-1a3bf3beaa71",
"parameters": {
"text": "=🚨 URGENT EMAIL REQUIRES REPLY\n\n*From:* {{ $('Extract Email Data').item.json.sender.value[0].address }}\n*Subject:* {{ $('Extract Email Data').item.json.subject }}\n*Received:* {{ $('Extract Email Data').item.json.receivedDate }}\n\n*AI Summary:*\n{{ $json.aiAnalysis.summary }}\n\n*Action Required:* {{ $json.aiAnalysis.callToAction }}\n*Insights:* {{ $json.aiAnalysis.insights }}\n",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "list",
"value": "C09H21LK9BJ",
"cachedResultName": "reply-needed"
},
"otherOptions": {}
},
"credentials": {
"slackApi": {
"id": "rNqvWj9TfChPVRYY",
"name": "Slack account vivek"
}
},
"typeVersion": 2
},
{
"id": "09091b5d-fbae-4fb4-b23c-077a7b59d36f",
"name": "Slack Attachments",
"type": "n8n-nodes-base.slack",
"position": [
336,
608
],
"webhookId": "9e25a820-c2f1-4639-91ad-aa55a1a2d976",
"parameters": {
"text": "=📎 EMAIL WITH ATTACHMENTS TO REVIEW\n\n*From:* {{ $('Extract Email Data').item.json.sender.value[0].address }}\n*Subject:* {{ $('Extract Email Data').item.json.subject }}\n*Received:* {{ $('Extract Email Data').item.json.receivedDate }}\n\n*AI Summary:*\n{{ $json.aiAnalysis.summary }}\n\n*Action Required:* {{ $json.aiAnalysis.callToAction }}\n*Insights:* {{ $json.aiAnalysis.insights }} \n\n*Links* {{ $json.output.links }}\n\n\n",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "list",
"value": "C09G3QM1NUT",
"cachedResultName": "review-needed"
},
"otherOptions": {}
},
"credentials": {
"slackApi": {
"id": "rNqvWj9TfChPVRYY",
"name": "Slack account vivek"
}
},
"typeVersion": 2
},
{
"id": "e752f272-dc3f-4e8b-a9c7-729cfd1a9862",
"name": "Slack General",
"type": "n8n-nodes-base.slack",
"position": [
336,
800
],
"webhookId": "4f99f77b-98ab-4dd9-b6c2-c4284c6ebfbe",
"parameters": {
"text": "=📧 EMAIL FOR YOUR INFORMATION\n\n*From:* {{ $('Extract Email Data').item.json.sender.value[0].address }}\n*Subject:* {{ $('Extract Email Data').item.json.subject }}\n*Received:* {{ $('Extract Email Data').item.json.receivedDate }}\n\n*AI Summary:*\n{{ $json.aiAnalysis.summary }}\n\n*Action Required:* {{ $json.aiAnalysis.callToAction }}\n*Insights:* {{ $json.aiAnalysis.insights }} ",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "list",
"value": "C09GNB90TED",
"cachedResultName": "general-information"
},
"otherOptions": {}
},
"credentials": {
"slackApi": {
"id": "rNqvWj9TfChPVRYY",
"name": "Slack account vivek"
}
},
"typeVersion": 2
},
{
"id": "93b2c1f4-b532-4102-aef9-42fd0192b6ba",
"name": "Structured Output Parser",
"type": "@n8n/n8n-nodes-langchain.outputParserStructured",
"position": [
-544,
832
],
"parameters": {
"jsonSchemaExample": "{\n \"summary\": \"string\",\n \"callToAction\": \"Reply Needed | Review Attachment | For Your Information\",\n \"insights\": \"string\",\n \"links\": [\"string\"],\n \"attachments\": [\"string\"]\n}\n"
},
"typeVersion": 1.3
},
{
"id": "80a7ba77-5601-4a8b-a45d-5dea98b1d112",
"name": "Azure OpenAI Chat Model1",
"type": "@n8n/n8n-nodes-langchain.lmChatAzureOpenAi",
"position": [
-800,
832
],
"parameters": {
"model": "gpt-4o",
"options": {}
},
"credentials": {
"azureOpenAiApi": {
"id": "C3WzT18XqF8OdVM6",
"name": "Azure Open AI account"
}
},
"typeVersion": 1
},
{
"id": "c9b3832f-eef9-4c7f-a7a0-b5585cf5b610",
"name": "Simple Memory1",
"type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
"position": [
-672,
832
],
"parameters": {
"sessionKey": "\"json_review\"",
"sessionIdType": "customKey",
"contextWindowLength": 7
},
"typeVersion": 1.3
},
{
"id": "5a329a24-6335-4f09-aed3-c410023c520d",
"name": "AI Agent",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
-752,
608
],
"parameters": {
"text": "={{ $json.subject }},{{ $json.bodyForAnalysis }}{{ $json.bodyHtml }}{{ $json.links }}",
"options": {
"systemMessage": "=You are an AI email assistant. Analyze the provided email content (subject, body text, HTML, and links) and return a structured JSON with the following fields:\n\n- summary: A concise plain text summary of the email.\n- callToAction: Choose one of [\"Reply Needed\", \"Review Attachment\", \"For Your Information\"] based on the email’s intent.\n- insights: Key points, deadlines, or important notes mentioned in the email.\n- links: Extract all valid links from the email content. If none are present, return an empty array [].\n- attachments: If attachments are mentioned in the text, list them as [\"PDF\", \"Excel\", \"Word\"] or return [].\n\nAlways respond with valid JSON only.\n"
},
"promptType": "define",
"hasOutputParser": true
},
"typeVersion": 2.1
},
{
"id": "87dededf-da46-4af9-9537-5a837f8bc3f8",
"name": "Log to Google Sheets",
"type": "n8n-nodes-base.googleSheets",
"position": [
784,
608
],
"parameters": {
"columns": {
"value": {},
"schema": [
{
"id": "timestamp",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "timestamp",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "sender",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "sender",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "subject",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "subject",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "ai_summary",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "ai_summary",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "action_required",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "action_required",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "slack_channel",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "slack_channel",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "has_attachments",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "has_attachments",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "autoMapInputData",
"matchingColumns": [
"id"
],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "appendOrUpdate",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1w_oZJKqp8sX4IAGs_UuAIx6U-ztqKsOpkTa7plhUQ3E/edit#gid=0",
"cachedResultName": "Sheet1"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "1w_oZJKqp8sX4IAGs_UuAIx6U-ztqKsOpkTa7plhUQ3E",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1w_oZJKqp8sX4IAGs_UuAIx6U-ztqKsOpkTa7plhUQ3E/edit?usp=drivesdk",
"cachedResultName": "Emails Sync data"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"id": "kpPEOLCGn963qpoh",
"name": "automations@techdome.ai"
}
},
"typeVersion": 4
},
{
"id": "e8db91ad-dbbf-47de-9ad0-c632909dc1ad",
"name": "Code",
"type": "n8n-nodes-base.code",
"position": [
560,
608
],
"parameters": {
"jsCode": "// Format only essential data for Google Sheets logging\nconst slackResponse = items[0].json;\nconst slackMessage = slackResponse.message || {};\nconst messageText = slackMessage.text || '';\n\n// Extract key information from Slack message\nconst fromMatch = messageText.match(/\\*From:\\*\\s*(?:<mailto:([^|>]+)\\|([^>]+)>|([^\\n*]+))/);\nconst subjectMatch = messageText.match(/\\*Subject:\\*\\s*([^\\n*]+)/);\nconst summaryMatch = messageText.match(/\\*AI Summary:\\*\\s*([\\s\\S]*?)(?=\\n\\n\\*|\\n\\*|$)/);\nconst actionMatch = messageText.match(/\\*Action Required:\\*\\s*([^\\n*]+)/);\n\n// Determine channel based on message content\nlet channelName = '#general';\nif (messageText.includes('URGENT EMAIL REQUIRES REPLY')) {\n channelName = '#urgent';\n} else if (messageText.includes('EMAIL WITH ATTACHMENTS')) {\n channelName = '#attachments';\n}\n\n// Check for attachments\nconst hasAttachments = messageText.includes('📎') || messageText.includes('Attachments');\n\n// Essential data only (6-7 columns)\nconst essentialData = {\n timestamp: new Date().toISOString(),\n sender: fromMatch?.[1] || fromMatch?.[2] || fromMatch?.[3] || 'Unknown',\n subject: subjectMatch?.[1]?.trim() || 'Unknown',\n ai_summary: summaryMatch?.[1]?.trim().replace(/\\n/g, ' ').substring(0, 200) || 'No summary',\n action_required: actionMatch?.[1]?.trim() || 'For Your Information',\n slack_channel: channelName,\n has_attachments: hasAttachments\n};\n\nreturn [{\n json: essentialData\n}];"
},
"typeVersion": 2
},
{
"id": "76c9328a-719f-4fc0-9328-920d6da6b216",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1536,
208
],
"parameters": {
"height": 400,
"content": "## 🔧 Extract Email Data\nProcesses raw Gmail data and extracts key information.\n\n**Details:**\n- Extracts sender, subject, body text/HTML\n- Identifies and extracts all links from email content\n- Advanced attachment detection using multiple methods\n- Checks for attachment keywords in email text\n- Prepares clean data structure for AI analysis\n"
},
"typeVersion": 1
},
{
"id": "f76d4704-8586-4793-ba03-764aa910629d",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2016,
544
],
"parameters": {
"height": 304,
"content": "## 📧 Gmail Trigger\nMonitors your **Gmail inbox** for new incoming emails.\n\n**Details:**\n- Polls Gmail every minute for new messages\n- Uses OAuth2 authentication\n- Triggers the workflow when new emails arrive\n- Provides raw email data to the next node.\n"
},
"typeVersion": 1
},
{
"id": "28ca059c-fe2f-4bc6-857e-d580d2170114",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-752,
176
],
"parameters": {
"height": 400,
"content": "## 🎯 AI Agent\nCore AI engine that analyzes email content and generates insights.\n\n**Details:**\n- Analyzes subject, body text, HTML, and links\n- Categorizes emails by urgency and action required\n- Extracts key insights, deadlines, and important notes\n- Uses structured output parser for consistent JSON responses\n- Connected to OpenAI model and memory for context"
},
"typeVersion": 1
},
{
"id": "380d301a-47ef-4271-83af-f1fa7838abd7",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1088,
848
],
"parameters": {
"height": 336,
"content": "## ⏭️ Skip Attachments\nBypass attachment processing for emails without attachments.\n\n**Details:**\n- Sets empty processedAttachments array\n- Uses only email body content for analysis\n- Maintains data structure consistency\n- Flags attachment processing as complete"
},
"typeVersion": 1
},
{
"id": "5a52def0-ef68-4220-b883-59a9e6b12f97",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1120,
48
],
"parameters": {
"height": 400,
"content": "## 📎 Process Attachments\nAnalyzes and processes email attachments when present.\n\n**Details:**\n- Identifies attachment types (text, PDF, Word)\n- Extracts metadata (filename, size, content type)\n- Combines attachment info with email content\n- Prepares enhanced content for AI analysis\n- Limits combined content to 4000 characters"
},
"typeVersion": 1
},
{
"id": "276b34ce-62ab-40ef-b1b6-669aa8675978",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1440,
784
],
"parameters": {
"height": 368,
"content": "## ❓ Check Attachments\nDecision node that routes emails based on attachment presence.\n\n**Details:**\n- Evaluates if email has attachments\n- Routes to 'Process Attachments' if attachments found\n- Routes to 'Skip Attachments' if no attachments\n- Uses boolean logic for attachment detection"
},
"typeVersion": 1
},
{
"id": "427d163f-0133-4a9b-8d3d-93de608e1445",
"name": "Sticky Note6",
"type": "n8n-nodes-base.stickyNote",
"position": [
560,
128
],
"parameters": {
"height": 432,
"content": "## 🔧 Format Data for Sheets\nPrepares and formats data for Google Sheets logging.\n\n**Details:**\n- Extracts essential information from Slack messages\n- Parses sender, subject, AI summary, and action required\n- Determines which Slack channel was used\n- Creates clean, structured data for spreadsheet\n- Limits text fields to appropriate lengths for sheets"
},
"typeVersion": 1
},
{
"id": "d51337f2-1cae-45a0-aadc-d307d6c3004a",
"name": "Sticky Note7",
"type": "n8n-nodes-base.stickyNote",
"position": [
672,
832
],
"parameters": {
"height": 368,
"content": "## 📎 Slack Attachments\nSends attachment email notifications to review channel.\n\n**Details:**\n- Posts to #review-needed channel\n- Includes attachment indicator emoji\n- Shows extracted links from email\n- Provides AI summary and insights\n- Prompts for attachment review action\n"
},
"typeVersion": 1
},
{
"id": "38c03951-45f4-4820-8a16-952ab81c6a39",
"name": "Sticky Note8",
"type": "n8n-nodes-base.stickyNote",
"position": [
208,
16
],
"parameters": {
"height": 336,
"content": "## 🚨 Slack Urgent\nSends urgent email notifications to priority Slack channel.\n\n**Details:**\n- Posts to #reply-needed channel\n- Includes sender, subject, AI summary\n- Highlights urgent nature with emoji\n- Contains action required and insights\n- Formatted for immediate attention"
},
"typeVersion": 1
},
{
"id": "d928682f-8c44-466c-be80-43a59f7fe312",
"name": "Sticky Note9",
"type": "n8n-nodes-base.stickyNote",
"position": [
336,
1008
],
"parameters": {
"height": 368,
"content": "## 📎 Slack Attachments\nSends attachment email notifications to review channel.\n\n**Details:**\n- Posts to #review-needed channel\n- Includes attachment indicator emoji\n- Shows extracted links from email\n- Provides AI summary and insights\n- Prompts for attachment review action"
},
"typeVersion": 1
},
{
"id": "05108295-8e4c-4256-8b44-807921e31481",
"name": "Sticky Note10",
"type": "n8n-nodes-base.stickyNote",
"position": [
-16,
896
],
"parameters": {
"height": 352,
"content": "## 📎 Route Attachments\nRoutes emails with attachments that need review.\n\n**Details:**\n- Checks if callToAction equals 'Review Attachment'\n- Sends attachment emails to dedicated Slack channel\n- Routes informational emails to general channel\n- Second-level priority routing decision"
},
"typeVersion": 1
},
{
"id": "950030af-00be-4ec7-84b7-8df2aa13adf4",
"name": "Sticky Note11",
"type": "n8n-nodes-base.stickyNote",
"position": [
-144,
288
],
"parameters": {
"height": 304,
"content": "## 🚨 Route Urgent\nRoutes urgent emails that require immediate reply.\n\n**Details:**\n- Checks if callToAction equals 'Reply Needed'\n- Sends urgent emails to dedicated Slack channel\n- Routes non-urgent emails to attachment check\n- First-level priority routing decision"
},
"typeVersion": 1
},
{
"id": "12a423f0-60d5-4b1d-8ecc-7be9cd38eaa9",
"name": "Sticky Note12",
"type": "n8n-nodes-base.stickyNote",
"position": [
-432,
176
],
"parameters": {
"height": 416,
"content": "## 🧠 Parse AI Response\nProcesses and validates AI analysis results.\n\n**Details:**\n- Handles multiple AI response formats\n- Extracts summary, callToAction, and insights\n- Validates callToAction values (Reply Needed, Review Attachment, For Your Information)\n- Provides fallback data if AI parsing fails\n- Combines AI results with original email data"
},
"typeVersion": 1
},
{
"id": "9a0c14ef-dc99-4055-b330-7f15c765689b",
"name": "Sticky Note13",
"type": "n8n-nodes-base.stickyNote",
"position": [
976,
704
],
"parameters": {
"height": 368,
"content": "## 📊 Log to Google Sheets\nRecords all processed emails in a Google Sheets database.\n\n**Details:**\n- Appends/updates email data in centralized spreadsheet\n- Maintains historical record of all processed emails\n- Uses OAuth2 authentication with Google Sheets API\n- Auto-maps input data to sheet columns\n- Provides audit trail and analytics capability"
},
"typeVersion": 1
},
{
"id": "bf7f53b9-b1e0-4df8-a20a-6e324bfb3b4c",
"name": "Sticky Note14",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1008,
1248
],
"parameters": {
"height": 336,
"content": "## 🤖 Azure OpenAI Chat Model\nProvides GPT-4o AI model for email analysis.\n\n**Details:**\n- Uses Azure OpenAI GPT-4o model\n- Processes email content for intelligent analysis\n- Generates structured responses\n- Connected to output parser for formatting"
},
"typeVersion": 1
},
{
"id": "90b58171-fa94-4608-8f7f-1396fee6e357",
"name": "Sticky Note15",
"type": "n8n-nodes-base.stickyNote",
"position": [
-688,
1024
],
"parameters": {
"height": 320,
"content": "## 🧠 Simple Memory\nProvides conversation memory for AI agent consistency.\n\n**Details:**\n- Maintains context across email analyses\n- Uses 7-message sliding window\n- Custom session key for email processing\n- Helps AI learn patterns and improve responses"
},
"typeVersion": 1
},
{
"id": "3b91f3d6-6a71-494d-8716-cd32284ece23",
"name": "Sticky Note16",
"type": "n8n-nodes-base.stickyNote",
"position": [
-368,
800
],
"parameters": {
"height": 352,
"content": "## 🏗️ Structured Output Parser\nDefines the expected JSON structure for AI responses.\n\n**Details:**\n- Enforces consistent AI output format\n- Specifies required fields (summary, callToAction, insights)\n- Validates callToAction options\n- Ensures structured data for downstream processing"
},
"typeVersion": 1
}
],
"active": false,
"pinData": {},
"settings": {
"executionOrder": "v1"
},
"versionId": "831a8262-6cf6-4bfc-90f2-dd19774de466",
"connections": {
"Code": {
"main": [
[
{
"node": "Log to Google Sheets",
"type": "main",
"index": 0
}
]
]
},
"AI Agent": {
"main": [
[
{
"node": "Parse AI Response",
"type": "main",
"index": 0
}
]
]
},
"Route Urgent": {
"main": [
[
{
"node": "Slack Urgent",
"type": "main",
"index": 0
}
],
[
{
"node": "Route Attachments",
"type": "main",
"index": 0
}
]
]
},
"Slack Urgent": {
"main": [
[
{
"node": "Code",
"type": "main",
"index": 0
}
]
]
},
"Gmail Trigger": {
"main": [
[
{
"node": "Extract Email Data",
"type": "main",
"index": 0
}
]
]
},
"Slack General": {
"main": [
[
{
"node": "Code",
"type": "main",
"index": 0
}
]
]
},
"Simple Memory1": {
"ai_memory": [
[
{
"node": "AI Agent",
"type": "ai_memory",
"index": 0
}
]
]
},
"Skip Attachments": {
"main": [
[
{
"node": "AI Agent",
"type": "main",
"index": 0
}
]
]
},
"Check Attachments": {
"main": [
[
{
"node": "Process Attachments",
"type": "main",
"index": 0
}
],
[
{
"node": "Skip Attachments",
"type": "main",
"index": 0
}
]
]
},
"Parse AI Response": {
"main": [
[
{
"node": "Route Urgent",
"type": "main",
"index": 0
}
]
]
},
"Route Attachments": {
"main": [
[
{
"node": "Slack Attachments",
"type": "main",
"index": 0
}
],
[
{
"node": "Slack General",
"type": "main",
"index": 0
}
]
]
},
"Slack Attachments": {
"main": [
[
{
"node": "Code",
"type": "main",
"index": 0
}
]
]
},
"Extract Email Data": {
"main": [
[
{
"node": "Check Attachments",
"type": "main",
"index": 0
}
]
]
},
"Process Attachments": {
"main": [
[
{
"node": "AI Agent",
"type": "main",
"index": 0
}
]
]
},
"Azure OpenAI Chat Model1": {
"ai_languageModel": [
[
{
"node": "AI Agent",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Structured Output Parser": {
"ai_outputParser": [
[
{
"node": "AI Agent",
"type": "ai_outputParser",
"index": 0
}
]
]
}
}
}常见问题
如何使用这个工作流?
复制上方的 JSON 配置代码,在您的 n8n 实例中创建新工作流并选择「从 JSON 导入」,粘贴配置后根据需要修改凭证设置即可。
这个工作流适合什么场景?
高级
需要付费吗?
本工作流完全免费,您可以直接导入使用。但请注意,工作流中使用的第三方服务(如 OpenAI API)可能需要您自行付费。
相关工作流推荐
客户入职帮助请求(Typeform 到 Gmail 和 Sheets)
客户入职帮助请求(Typeform 到 Gmail 和 Sheets)
If
Code
Gmail
+10
28 节点Rahul Joshi
内容创作
自动化从ClickUp和GoHighLevel生成每日结束报告到Slack、Email和Google云端硬盘
从ClickUp和GoHighLevel生成AI驱动的每日结束报告到多渠道
If
Code
Merge
+12
29 节点Rahul Joshi
使用GPT-4自动化从ClickUp到Slack和Gmail的每日晨报生成
使用GPT-4o从ClickUp生成AI驱动的晨报并发送至Slack和Gmail
If
Code
Gmail
+9
27 节点Rahul Joshi
支持收件箱到常见问题解答回填(Gmail/Outlook)
使用GPT-4o、Gmail、Notion和Slack将支持邮件转换为常见问题解答
If
Code
Gmail
+7
21 节点Rahul Joshi
工单管理
从Monday.com和Jira到Outlook的AI驱动反馈分类与报告
使用Azure GPT-4、Jira任务和Outlook报告分析来自Monday.com的客户反馈
Set
Code
Jira
+12
27 节点Rahul Joshi
代码注释转FAQ同步 (GitHub)
使用GPT-4o、Notion和Slack为开发团队自动回答GitHub PR问题
If
Code
Slack
+6
18 节点Rahul Joshi
工程
工作流信息
难度等级
高级
节点数量34
分类-
节点类型10
作者
Rahul Joshi
@rahul08Rahul Joshi is a seasoned technology leader specializing in the n8n automation tool and AI-driven workflow automation. With deep expertise in building open-source workflow automation and self-hosted automation platforms, he helps organizations eliminate manual processes through intelligent n8n ai agent automation solutions.
外部链接
在 n8n.io 查看 →
分享此工作流