HomeAI AutomationHow to Auto-Triage Support Emails to…
AI Automation

How to Auto-Triage Support Emails to Slack with AI Using n8n

How to Auto-Triage Support Emails to Slack with AI Using n8n

Every support inbox gets noisy fast. A billing question sits next to a frantic “our entire account is locked” message, and both look the same in a Gmail preview. By the time someone reads the urgent one, an hour has slipped by. This tutorial walks you through building an n8n workflow that reads every inbound support email, asks GPT-4o mini to classify it by priority and category, routes the result to the right Slack channel — and logs everything to a Google Sheet so nothing ever disappears.

Prefer to skip the setup? Grab the ready-made template → and be up and running in under 10 minutes.

What You’ll Build

  1. A Gmail trigger polls your inbox every minute for new unread emails.
  2. An OpenAI call analyzes the email and returns a priority level (High / Medium / Low), a category (Bug Report, Billing, Feature Request, etc.), a one-sentence summary, and the sender’s detected sentiment.
  3. A conditional branch routes High-priority tickets to a #support-urgent Slack channel with a bold alert, and everything else to #support as a standard notification.
  4. Every ticket — regardless of priority — is appended to a Google Sheet so you have a permanent, searchable log of all incoming requests.

How It Works — The Big Picture

The workflow runs as a polling loop. Think of it as a tireless assistant who checks email every sixty seconds, reads it with an AI brain, and instantly posts into the right Slack channel — then files the paperwork in a spreadsheet.

┌─────────────────────────────────────────────────────────────────────┐
│  GMAIL → SLACK AI SUPPORT TRIAGE                                    │
│                                                                     │
│  [Gmail Trigger]                                                    │
│       │  (new unread email)                                         │
│       ▼                                                             │
│  [Extract Email Fields]                                             │
│       │  (sender, subject, body snippet, timestamp)                 │
│       ▼                                                             │
│  [AI Classify & Summarize]  ←── OpenAI gpt-4o-mini                 │
│       │  (priority, category, summary, sentiment)                   │
│       ▼                                                             │
│  [Parse AI Response]                                                │
│       │                                                             │
│       ▼                                                             │
│  [Check Priority]                                                   │
│       │                        │                                    │
│    priority=High           priority≠High                            │
│       │                        │                                    │
│       ▼                        ▼                                    │
│  [Slack Urgent]          [Slack Standard]                           │
│  #support-urgent          #support                                  │
│       │                        │                                    │
│       └──────────┬─────────────┘                                    │
│                  ▼                                                  │
│         [Log to Google Sheets]                                      │
└─────────────────────────────────────────────────────────────────────┘

What You’ll Need

  • n8n — self-hosted or n8n Cloud (any version 1.0+)
  • Gmail account — connected via Google OAuth2 in n8n
  • OpenAI account — API key with access to gpt-4o-mini
  • Slack workspace — with two channels: #support-urgent and #support
  • Google Sheets — a spreadsheet with the columns described below

Estimated build time: 40–60 minutes from scratch, or under 10 minutes with the template.


Building the Workflow — Step by Step

1 Gmail Trigger — Watch for New Emails

The Gmail Trigger node polls your inbox every minute and fires once for each new unread email it finds. Connect your Gmail credential via Google OAuth2, set Poll Times to Every Minute, and set Read Status to Unread under Filters.

After a test run, the raw payload looks like this:

{
  "id": "18f4a3b2c1d0e9f8",
  "from": { "value": [{ "name": "Sarah Thompson", "address": "sarah.thompson@outlook.com" }] },
  "subject": "Can't log into my account — urgent!",
  "text": "Hi, I've been trying to log in for the past hour and keep getting an 'Invalid credentials' error...",
  "date": "2026-04-03T14:22:00.000Z"
}
💡

Tip: If you only want to monitor a specific support address, route emails to a Gmail label first, then filter by that label in the trigger node.

2 Extract Email Fields — Set Node

The Set node flattens the nested Gmail payload into a clean, flat object for the AI prompt. Configure these assignments:

Field Name Expression Purpose
sender ={{ $json.from?.value?.[0]?.address ?? $json.from }} Sender’s email address
senderName ={{ $json.from?.value?.[0]?.name ?? 'Unknown' }} Sender’s display name
subject ={{ $json.subject ?? '(No Subject)' }} Email subject line
bodySnippet ={{ ($json.text ?? $json.snippet ?? '').substring(0, 1200) }} First 1,200 chars of body
receivedAt ={{ $now.format('yyyy-MM-dd HH:mm') }} Human-readable timestamp
messageId ={{ $json.id }} Gmail message ID
📌

We cap the body at 1,200 characters to keep OpenAI token costs low. Increase this limit if your customers tend to write detailed reports.

3 AI Classify & Summarize — HTTP Request to OpenAI

An HTTP Request node sends the email to OpenAI’s Chat Completions API. Set Method to POST, URL to https://api.openai.com/v1/chat/completions, and Authentication to HTTP Header Auth with Authorization: Bearer YOUR_KEY. Use this JSON body:

{
  "model": "gpt-4o-mini",
  "temperature": 0,
  "response_format": { "type": "json_object" },
  "messages": [
    { "role": "system", "content": "You are a support triage assistant. Return JSON with: priority (High/Medium/Low), category (Bug Report/Billing/Feature Request/General Question/Account Issue), summary (max 120 chars), sentiment (Frustrated/Neutral/Positive). High priority = outage, data loss, billing error, account locked, urgent/ASAP." },
    { "role": "user", "content": "From: {{ $json.senderName }} <{{ $json.sender }}>\nSubject: {{ $json.subject }}\n\n{{ $json.bodySnippet }}" }
  ]
}
💡

Tip: Setting temperature: 0 makes classification deterministic. The response_format: json_object parameter guarantees the response is always valid JSON, preventing parse errors downstream.

4 Parse AI Response — Code Node

This Code node extracts the nested JSON, parses it, and merges AI classifications with the original email fields:

const aiRaw = items[0].json.choices?.[0]?.message?.content ?? '{}';
let ai;
try { ai = JSON.parse(aiRaw); }
catch (e) { ai = { priority: 'Low', category: 'General Question', summary: 'Parse error', sentiment: 'Neutral' }; }

const emailData = $('Extract Email Fields').item.json;
return [{ json: {
  sender: emailData.sender, senderName: emailData.senderName,
  subject: emailData.subject, bodySnippet: emailData.bodySnippet,
  receivedAt: emailData.receivedAt, messageId: emailData.messageId,
  priority: ai.priority ?? 'Low', category: ai.category ?? 'General Question',
  summary: ai.summary ?? emailData.subject, sentiment: ai.sentiment ?? 'Neutral'
}}];

The merged output object looks like this:

{
  "sender": "sarah.thompson@outlook.com",
  "senderName": "Sarah Thompson",
  "subject": "Can't log into my account — urgent!",
  "priority": "High",
  "category": "Account Issue",
  "summary": "User cannot log in due to 'Invalid credentials' error persisting for over an hour.",
  "sentiment": "Frustrated",
  "receivedAt": "2026-04-03 14:22",
  "messageId": "18f4a3b2c1d0e9f8"
}
💡

Tip: The try/catch block ensures the workflow never crashes if OpenAI is rate-limited or returns an unexpected response — it falls back to Low priority instead.

5 Check Priority — IF Node

The IF node checks whether priority equals "High" (case-insensitive). True branch → urgent Slack alert. False branch → standard notification. Left value: ={{ $json.priority }}, Operation: String equals, Right value: High.

📌

To add a Medium-priority route, swap the IF node for a Switch node with three outputs: High, Medium, and Low.

6 Slack Urgent Alert

Posts to #support-urgent with Block Kit formatting. Set Resource to Message, Operation to Post, Message Type to Blocks. The card shows sender name, category, received timestamp, sentiment, subject, and AI summary — everything your on-call team needs at a glance.

💡

Tip: Add an Action block with a button linking directly to the email: https://mail.google.com/mail/u/0/#inbox/{{ $json.messageId }}

7 Slack Standard Alert

Identical configuration to Step 6, but posts to #support with a gentler 📬 New Support Ticket header and includes the priority level in the fields.

8 Log to Google Sheets

Both Slack branches converge here. The Google Sheets node appends one row per email. Set Operation to Append Row and map all nine columns. This creates a permanent, searchable history of every inbound request.


The Data Structure

Create a Google Sheet named Support Ticket Log with these columns in row 1. Names are case-sensitive and must match exactly.

Column Type Example Description
Received At Text 2026-04-03 14:22 Timestamp when the email arrived
Sender Text sarah.thompson@outlook.com Sender’s email address
Sender Name Text Sarah Thompson Sender’s display name from Gmail
Subject Text Can’t log into my account — urgent! Original email subject line
Priority Text High AI-assigned priority: High / Medium / Low
Category Text Account Issue AI-assigned ticket category
Sentiment Text Frustrated Detected sender emotion
AI Summary Text User cannot log in due to… One-sentence AI summary
Message ID Text 18f4a3b2c1d0e9f8 Gmail message ID for deduplication
📌

Column names are case-sensitive. Leaving out columns won’t break the workflow — n8n simply won’t write to unmapped columns.


Full System Flow

  INCOMING EMAIL
       │
       ▼
  ┌────────────────┐
  │  Gmail Trigger │  (polls every minute)
  └────────┬───────┘
           │ raw email payload
           ▼
  ┌──────────────────────┐
  │  Extract Email Fields │  (Set node)
  └──────────┬───────────┘
             │ {sender, subject, bodySnippet, receivedAt, messageId}
             ▼
  ┌──────────────────────────────┐
  │  AI Classify & Summarize     │  (HTTP → OpenAI gpt-4o-mini)
  └──────────┬───────────────────┘
             │ OpenAI JSON response
             ▼
  ┌──────────────────────┐
  │  Parse AI Response   │  (Code node)
  └──────────┬───────────┘
             │ {priority, category, summary, sentiment, + email fields}
             ▼
  ┌──────────────────────┐
  │    Check Priority    │  (IF node)
  └────┬─────────────────┘
       │                     │
  priority=High         priority≠High
       │                     │
       ▼                     ▼
  ┌────────────┐     ┌────────────────┐
  │ Slack      │     │ Slack          │
  │ #support-  │     │ #support       │
  │  urgent    │     │ (standard)     │
  └─────┬──────┘     └──────┬─────────┘
        │                   │
        └──────────┬────────┘
                   ▼
       ┌────────────────────┐
       │  Log to Google     │
       │  Sheets (append)   │
       └────────────────────┘

Testing Your Workflow

  1. Activate the workflow (toggle the Active switch in the top-right).
  2. Send a test email with subject “URGENT: payment failed — please help!” to the monitored inbox.
  3. Wait up to 60 seconds, then check #support-urgent in Slack — you should see a card with a bold header.
  4. Check your Google Sheet — a new row should appear with all nine columns filled.
  5. Send a second email with subject “Feature request: dark mode”. It should appear in #support as Low priority.
Problem Likely Cause Fix
No Slack message received Slack credential scope missing Re-authorize Slack and ensure chat:write scope is granted
Google Sheets row not appended Column name mismatch Check that sheet column headers match exactly (case-sensitive)
OpenAI node returns 401 API key format wrong Verify the Authorization header value is Bearer sk-…
All emails classified as Low AI parse error falling back Inspect Code node output — check choices[0].message.content
Gmail trigger fires duplicates Emails re-marked as unread Enable the Mark as Read option on the Gmail Trigger node

Frequently Asked Questions

Does this workflow automatically reply to the sender?

No — this workflow focuses purely on triage and notification. You can add a Gmail send node at the end to fire an auto-acknowledgment, wired in parallel with the Slack nodes so both happen simultaneously.

How much does the OpenAI API cost to run this?

GPT-4o mini is very inexpensive — roughly $0.15 per million input tokens. For a typical support email (~200 tokens), you’re looking at fractions of a cent per email. Processing 1,000 emails per month costs less than $0.50 in API fees.

Can I add more priority levels or categories?

Absolutely. Edit the system prompt in the HTTP Request node to include any levels or categories you need. Just make sure your IF or Switch node branches match whatever the AI returns.

What happens if OpenAI is down or rate-limited?

The Code node has a try/catch block that falls back to Low priority if parsing fails. The email still gets logged to Google Sheets and posted to Slack — just without an AI classification.

Can I monitor multiple Gmail inboxes?

Yes. Add a second Gmail Trigger node connected to a different Gmail credential and wire it into the same Extract Email Fields node. Both triggers independently poll their inboxes and feed into the same triage pipeline.

Is my email content sent to OpenAI’s servers?

Yes — the subject and first 1,200 characters of the body are sent to OpenAI’s API. OpenAI’s standard API does not use submitted data to train models. If your emails contain sensitive data, consider a self-hosted local model like Ollama with Llama 3 via the HTTP Request node.


🚀 Get the Gmail → Slack AI Support Triage Template

Skip the build and get a ready-to-import n8n workflow JSON, a step-by-step Setup Guide PDF, and a Credentials Guide PDF — everything you need to be running in under 10 minutes.

Get the Template →

Instant download · Works on n8n Cloud and self-hosted

What’s Next?

  • Auto-reply on High priority: Add a Gmail send node that fires an immediate acknowledgment to the customer when their ticket lands as High priority.
  • Create tickets in a helpdesk: Replace or augment the Google Sheets node with a Zendesk, Freshdesk, or Linear node to create a real ticket with the AI-assigned priority already set.
  • Daily digest report: Add a second workflow that runs at 8 AM every morning, reads yesterday’s rows from the Google Sheet, and posts a summary to Slack.
  • Sentiment escalation: DM the support manager directly when sentiment is Frustrated AND priority is High.
n8n
Gmail
Slack
OpenAI
Google Sheets
Support Automation
AI Triage
automation