AutomationFlowsAI & RAG › Auto-draft Professional Email Replies with Gmail, Ai, and Slack

Auto-draft Professional Email Replies with Gmail, Ai, and Slack

Bykota @takasuka on n8n.io

This workflow monitors your Gmail inbox for new, unreplied emails and automatically generates a professional reply draft using AI. Instead of sending the email automatically, the draft is sent to Slack so a human can review and decide whether to send it.

Cron / scheduled trigger★★★★☆ complexityAI-powered16 nodesGmailOpenAISlack
AI & RAG Trigger: Cron / scheduled Nodes: 16 Complexity: ★★★★☆ AI nodes: yes Added:

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

This workflow follows the Gmail → OpenAI 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": "XvgV8qqLUG9Vayj2",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Professional Email Automation Framework",
  "tags": [],
  "nodes": [
    {
      "id": "f702a564-b299-4bc4-b5c4-19a38a127cfa",
      "name": "Schedule Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        0,
        0
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "minutes",
              "minutesInterval": 30
            }
          ]
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "5ba2106f-fa48-4a8f-9243-f5ab93d6fe5a",
      "name": "Limit - Max emails per run",
      "type": "n8n-nodes-base.limit",
      "position": [
        624,
        -96
      ],
      "parameters": {
        "maxItems": 5
      },
      "typeVersion": 1
    },
    {
      "id": "48e377b6-bbf4-4a6d-b873-bee34c7619fd",
      "name": "Gmail - Get message details",
      "type": "n8n-nodes-base.gmail",
      "position": [
        832,
        -96
      ],
      "parameters": {
        "messageId": "={{ $json.id }}",
        "operation": "get"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "d180af7a-0a91-4d3d-b7b9-740cea82a9eb",
      "name": "Search unreplied emails",
      "type": "n8n-nodes-base.gmail",
      "position": [
        208,
        0
      ],
      "parameters": {
        "limit": 10,
        "filters": {
          "q": "=in:inbox is:unread"
        },
        "operation": "getAll"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "f071cd47-4c2e-4e73-86fd-db6d1d9e0a52",
      "name": "Check if new emails exist",
      "type": "n8n-nodes-base.if",
      "position": [
        416,
        0
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "fee64c80-a6e5-42cb-aaec-5a1a73f01018",
              "operator": {
                "type": "number",
                "operation": "gt"
              },
              "leftValue": "={{$items().length}}",
              "rightValue": 0
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "856ba060-691f-4779-9c16-5d5acf13d6d5",
      "name": "Extract email body for AI",
      "type": "n8n-nodes-base.code",
      "position": [
        1040,
        -96
      ],
      "parameters": {
        "jsCode": "// Safely extract the email body text from the Gmail payload\n\nfunction decodeBase64(str) {\n  return Buffer.from(str, 'base64').toString('utf-8');\n}\n\nconst payload = $json.payload;\n\nlet body = '';\n\n// Case 1: Simple text/plain email body\nif (payload.body && payload.body.data) {\n  body = decodeBase64(payload.body.data);\n}\n\n// Case 2: Multipart email (e.g. text/plain + text/html)\nif (!body && payload.parts) {\n  for (const part of payload.parts) {\n    if (part.mimeType === 'text/plain' && part.body?.data) {\n      body = decodeBase64(part.body.data);\n      break;\n    }\n  }\n}\n\n// Fallback to snippet if full body is not available\nif (!body) {\n  body = $json.snippet || '';\n}\n\nreturn {\n  emailText: body.trim(),\n  subject: $json.snippet,\n  threadId: $json.threadId,\n  receivedAt: new Date(Number($json.internalDate)).toISOString()\n};\n"
      },
      "typeVersion": 2
    },
    {
      "id": "23239b95-5337-4285-bd74-4e9d132ce29b",
      "name": "AI - Draft professional email reply",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "position": [
        1248,
        -96
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4.1-mini",
          "cachedResultName": "GPT-4.1-MINI"
        },
        "options": {},
        "responses": {
          "values": [
            {
              "role": "system",
              "content": "You are a professional assistant who writes polite Japanese business emails.\nIf there are any points where the facts are unclear, do not make assumptions and instead confirm them by asking questions."
            },
            {
              "content": "=Please draft a polite and short reply to the email you received below.\n\nConditions: \n- Greetings at the beginning\n- Thanking the recipient\n- Answering the purpose of the email (don't guess, ask questions to confirm anything unclear)\n- Proposing next actions (potential dates/necessary information, etc.)\n- Closing greetings\n- Do not include a signature \n Body of the received email:\n{{ $json.emailText }}\n"
            }
          ]
        },
        "builtInTools": {}
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "59cdfe8b-7527-428a-bcf1-7dfd345e55ae",
      "name": "Notify draft reply in Slack",
      "type": "n8n-nodes-base.slack",
      "position": [
        1600,
        -96
      ],
      "parameters": {
        "text": "=\ud83d\udce9 There is an email that needs to be replied to\n\n[AI reply draft]\n{{ $node[\"AI - Draft professional email reply\"].json.output[0].content[0].text }}\n\n\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\u2015\n(This message is automatically generated.)\n",
        "select": "channel",
        "channelId": {
          "__rl": true,
          "mode": "list",
          "value": "C0A3FM8HDU3",
          "cachedResultName": "all-kota"
        },
        "otherOptions": {}
      },
      "credentials": {
        "slackApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.4
    },
    {
      "id": "4c787cfc-8bc0-4f5c-815e-d8432be82017",
      "name": "Mark email as AUTO_REPLIED",
      "type": "n8n-nodes-base.gmail",
      "position": [
        1040,
        128
      ],
      "parameters": {
        "labelIds": [
          "Label_5043339914715829876"
        ],
        "messageId": "={{ $json.id }}",
        "operation": "addLabels"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "9f39256e-b781-4109-a2dc-b897607dd9e7",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "disabled": true,
      "position": [
        992,
        -224
      ],
      "parameters": {
        "color": 7,
        "width": 544,
        "height": 304,
        "content": "## AI Draft Generation\nCreates a professional email reply draft using AI.\nHuman review required."
      },
      "typeVersion": 1
    },
    {
      "id": "f2204ee0-b63b-44ec-86d2-bb8224319766",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        992,
        112
      ],
      "parameters": {
        "color": 7,
        "width": 368,
        "height": 320,
        "content": "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n## \ud83d\udcec Notification & State Control\n \n\u2022 Sends AI-generated draft to Slack\n\u2022 Marks email as AUTO_REPLIED\n\u2022 Prevents duplicate processing\n"
      },
      "typeVersion": 1
    },
    {
      "id": "95899fba-a7c8-4cfb-8829-b78bff651dba",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1584,
        -224
      ],
      "parameters": {
        "color": 7,
        "width": 368,
        "height": 304,
        "content": "## \ud83d\udcec Notification & State Control\n \n\u2022 Sends AI-generated draft to Slack\n\u2022 Marks email as AUTO_REPLIED\n\u2022 Prevents duplicate processing\n"
      },
      "typeVersion": 1
    },
    {
      "id": "5ab4f131-9d33-49f3-b3db-bb8fbb97a3b7",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -48,
        -752
      ],
      "parameters": {
        "width": 640,
        "height": 592,
        "content": "## I'm a note \n\nThis is a professional email automation framework\nThis workflow monitors your Gmail inbox on a schedule and looks for new, unreplied emails.\n\nWhen a new email is found, it:\n- Retrieves the full email content\n- Extracts the plain text body safely\n- Generates a professional reply draft using AI\n- Sends the draft to Slack for human review\n- Labels the email to prevent duplicate processing\n\nThe workflow does NOT send emails automatically.\nIt only creates draft replies for review.\n\n## Setup steps\n\n1. Connect your Gmail account\n2. Create a Gmail label called AUTO_REPLIED\n3. Connect your OpenAI (or compatible) API credentials\n4. Connect your Slack workspace and choose a channel\n5. Adjust the schedule trigger if needed\n\nOnce set up, the workflow will run automatically."
      },
      "typeVersion": 1
    },
    {
      "id": "cce1a803-016e-4a5c-bc29-eaedf4895ab3",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -48,
        -112
      ],
      "parameters": {
        "color": 7,
        "width": 416,
        "height": 304,
        "content": "## Email Monitoring\nChecks Gmail for new unreplied emails on a schedule."
      },
      "typeVersion": 1
    },
    {
      "id": "5f7db3e2-083e-4380-b87d-7828e94bd59e",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        672,
        -560
      ],
      "parameters": {
        "width": 256,
        "height": 208,
        "content": "## How to customize this framework\nOptional nodes are intentionally left unconnected.\nUsers can plug them into the flow depending on their use case.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "d0d365a8-73dd-4ce0-bd89-f46fdf49cd40",
      "name": "OPTIONAL \u2013 Auto-send reply",
      "type": "n8n-nodes-base.if",
      "position": [
        1488,
        192
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "0f2f78fe-2e4c-4ab9-b719-d551ed4b65cd",
              "operator": {
                "name": "filter.operator.equals",
                "type": "string",
                "operation": "equals"
              },
              "leftValue": "",
              "rightValue": ""
            }
          ]
        }
      },
      "typeVersion": 2.3
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "8604479b-d27c-43bf-b468-c458584dc81a",
  "connections": {
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "Search unreplied emails",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Search unreplied emails": {
      "main": [
        [
          {
            "node": "Check if new emails exist",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check if new emails exist": {
      "main": [
        [
          {
            "node": "Limit - Max emails per run",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract email body for AI": {
      "main": [
        [
          {
            "node": "AI - Draft professional email reply",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Limit - Max emails per run": {
      "main": [
        [
          {
            "node": "Gmail - Get message details",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Gmail - Get message details": {
      "main": [
        [
          {
            "node": "Extract email body for AI",
            "type": "main",
            "index": 0
          },
          {
            "node": "Mark email as AUTO_REPLIED",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Notify draft reply in Slack": {
      "main": [
        []
      ]
    },
    "AI - Draft professional email reply": {
      "main": [
        [
          {
            "node": "Notify draft reply in Slack",
            "type": "main",
            "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 monitors your Gmail inbox for new, unreplied emails and automatically generates a professional reply draft using AI. Instead of sending the email automatically, the draft is sent to Slack so a human can review and decide whether to send it.

Source: https://n8n.io/workflows/11845/ — 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

A scheduled process aggregates content from eight distinct data sources and standardizes all inputs into a unified format. AI models perform sentiment scoring, detect conspiracy or misinformation sign

HTTP Request, OpenAI, Postgres +2
AI & RAG

Imagine a dedicated financial expert tirelessly working behind the scenes, sifting through every transaction, every investment move, and every accounting entry. That's exactly what this automated syst

HTTP Request, Google Sheets, OpenAI +3
AI & RAG

Property management companies, building managers, and inspection teams who want to automate recurring property inspections, improve issue tracking, and streamline reporting.

Google Sheets, OpenAI, Gmail +2
AI & RAG

Business owners and service providers who want to reduce no-show rates for appointments booked via Google Calendar.

Google Calendar, Google Sheets, OpenAI +2
AI & RAG

This workflow runs on a daily schedule to analyze all Closed–Lost deals from your CRM and uncover the true reason behind each loss. It uses AI to classify the primary loss category, generate a confide

HubSpot, Slack, Gmail +2