AutomationFlowsAI & RAG › Smart Email Triage with Gmail, Gpt-4, Slack and Google Sheets

Smart Email Triage with Gmail, Gpt-4, Slack and Google Sheets

ByRahul Joshi @rahul08 on n8n.io

This workflow intelligently analyzes incoming Gmail emails, classifies intent using GPT-4, and sends real-time Slack notifications while logging structured data into Google Sheets. It provides a smart, AI-assisted communication workflow that saves time and ensures no important…

Event trigger★★★★★ complexityAI-powered34 nodesGmail TriggerSlackOutput Parser StructuredLm Chat Azure Open AiMemory Buffer WindowAgentGoogle Sheets
AI & RAG Trigger: Event Nodes: 34 Complexity: ★★★★★ AI nodes: yes Added:

This workflow corresponds to n8n.io template #9680 — we link there as the canonical source.

This workflow follows the Agent → Gmail Trigger 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 →

Download .json
{
  "id": "EkrH16IadUZrhHQT",
  "meta": {
    "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": {
          "name": "<your credential>"
        }
      },
      "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
      ],
      "parameters": {
        "text": "=\ud83d\udea8 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": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "09091b5d-fbae-4fb4-b23c-077a7b59d36f",
      "name": "Slack Attachments",
      "type": "n8n-nodes-base.slack",
      "position": [
        336,
        608
      ],
      "parameters": {
        "text": "=\ud83d\udcce 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": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2
    },
    {
      "id": "e752f272-dc3f-4e8b-a9c7-729cfd1a9862",
      "name": "Slack General",
      "type": "n8n-nodes-base.slack",
      "position": [
        336,
        800
      ],
      "parameters": {
        "text": "=\ud83d\udce7 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": {
          "name": "<your credential>"
        }
      },
      "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": {
          "name": "<your credential>"
        }
      },
      "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\u2019s 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": {
          "name": "<your credential>"
        }
      },
      "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('\ud83d\udcce') || 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": "## \ud83d\udd27 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": "## \ud83d\udce7 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": "## \ud83c\udfaf 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": "## \u23ed\ufe0f 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": "## \ud83d\udcce 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": "## \u2753 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": "## \ud83d\udd27 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": "## \ud83d\udcce 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": "## \ud83d\udea8 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": "## \ud83d\udcce 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": "## \ud83d\udcce 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": "## \ud83d\udea8 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": "## \ud83e\udde0 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": "## \ud83d\udcca 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": "## \ud83e\udd16 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": "## \ud83e\udde0 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": "## \ud83c\udfd7\ufe0f 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,
  "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
          }
        ]
      ]
    }
  }
}

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.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

This workflow intelligently analyzes incoming Gmail emails, classifies intent using GPT-4, and sends real-time Slack notifications while logging structured data into Google Sheets. It provides a smart, AI-assisted communication workflow that saves time and ensures no important…

Source: https://n8n.io/workflows/9680/ — original creator credit. Request a take-down →

More AI & RAG workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

AI & RAG

This workflow automates end-to-end validation, assessment, and reporting of n8n workflow JSON templates using Google Drive, Azure OpenAI GPT-4o, Gmail, and Slack. It retrieves workflows from a Drive f

Memory Buffer Window, Lm Chat Azure Open Ai, Output Parser Structured +5
AI & RAG

Automatically capture customer onboarding help requests from Typeform, log them in Google Sheets, validate email addresses, and send a professional HTML welcome email via Gmail. Ensures smooth onboard

Typeform Trigger, Google Sheets, Gmail +6
AI & RAG

Streamline your HR recruitment process with this intelligent automation that reads candidate emails and resumes, analyzes them using GPT-4, and automatically shortlists or rejects applicants based on

Gmail, Gmail Trigger, HTTP Request +7
AI & RAG

CV → Match → Screen → Decide, all automated

HTTP Request, Information Extractor, Google Sheets +7
AI & RAG

Streamline customer support with a real-time, AI-powered answer engine that detects incoming support emails, classifies intent, identifies the customer’s GEO region, and generates a tailored reply rea

Slack, Gmail Trigger, OpenAI Chat +5