8
n8n 中文网amn8n.com

基于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

分类

-
工作流预览
可视化展示节点连接关系,支持缩放和平移
导出工作流
复制以下 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)可能需要您自行付费。

工作流信息
难度等级
高级
节点数量34
分类-
节点类型10
难度说明

适合高级用户,包含 16+ 个节点的复杂工作流

作者
Rahul Joshi

Rahul Joshi

@rahul08

Rahul 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 查看

分享此工作流