Case studies
CASE STUDY — AI

CS ticket auto-triage — Gmail reads, AI classifies category + priority + drafts a reply

Deployed at Subscription / SaaS5 days to build
GmailOpenAISlackn8n Schedule

Tickets piled up in one inbox, all mixed together. While someone read through them one by one, sorting by type and handing them off, urgent issues got buried among the routine ones. A payment error that arrived overnight would only be spotted in the afternoon — over and over.

We handed that first read-and-sort step to AI. But we split it: judgment automatic, sending manual. AI produces the category, priority, and reply draft; a human opens the draft from Gmail's Drafts folder and reviews, edits, and sends within 5 seconds. It's a safety net for when classification is wrong, and an observation window for prompt tuning in the first few weeks.

cs-triage.workflowLIVE
GMRead GmailAIClassify + draftDRSave draftSLSlack summary

How it works

  1. A Schedule Trigger node kicks off every 10 minutes (swap in a Gmail Trigger if you need real-time).
  2. A Gmail Get Many node pulls only new CS mail via label:cs-inbox is:unread. The cs-inbox label is applied automatically by a Gmail filter based on your CS address / forwarding rules.
  3. For each email, a Code node cleans up the subject and body and builds the messages array for OpenAI (the Code node's Run Once for Each Item mode is required).
  4. An HTTP Request node POSTs to https://api.openai.com/v1/chat/completions — with response_format: json_object set so the AI is forced to return valid JSON only.
  5. A Code node parses the AI JSON and normalizes it into {category, priority, reason, reply}.
  6. Three follow-up actions in parallel: Mark as Read prevents reprocessing on the next run · Create Draft Reply saves the response draft to Gmail's Drafts folder · Aggregate Summary + Slack Post announces the batch classification results to the team channel.

What you need

  • n8n 2.29.9 or later (self-hosted or Cloud). Verification was done on self-hosted Docker.
  • Gmail OAuth2 credentials — enable the Gmail API in a Google Cloud project and issue an OAuth 2.0 client. Required scopes: https://www.googleapis.com/auth/gmail.modify (mark as read) + https://www.googleapis.com/auth/gmail.compose (draft creation).
  • Gmail filter rule — Gmail Settings → Filters and Blocked Addresses → Create new filter. Auto-apply the cs-inbox label to mail matching conditions like to:cs@yourdomain.com. Create the label ahead of time.
  • OpenAI API key — payment method required. Register in n8n Credentials as OpenAI account. At 100 tickets/day, gpt-4o-mini runs under 1,000 KRW/month.
  • Slack Bot User OAuth Tokenchat:write, channels:read. /invite @your-bot in the target channel.
  • Slack channel — one your CS team watches. Per-batch summaries (category counts + urgent-item highlights) get posted here.

AI classification schema — this is the JSON it returns

{
  "category": "billing" | "technical" | "feature" | "general",
  "priority": "urgent" | "normal" | "low",
  "reason": "one sentence explaining why it was classified this way",
  "reply":  "a polite Korean draft for the team to review, edit, and send (2–3 paragraphs, including greeting)"
}

Actual classification results (batch of 4)

[billing/urgent]  Payment failed but the charge came off my card
  → A payment issue occurred and the card was already charged — needs urgent handling.

[technical/urgent]  API responses suddenly started returning 500 errors
  → API errors are producing 500s and there is a risk of service disruption.

[feature/normal]  Do you have plans to support SSO (OIDC)?
  → The user is asking about SSO (OIDC) support plans, classified as a feature request.

[technical/normal]  The homepage won't load
  → Homepage-not-loading issues fall under technical.
⬇︎ Download workflow (cs-triage.json)
Set up three credentials (Gmail, OpenAI, Slack) + your Slack channel name + a Gmail filter (auto-applying the `cs-inbox` label) and it runs immediately. Detailed steps are in the Sticky Note at the top of the workflow.
This workflow was verified on n8n 2.29.9 wired to real Gmail + OpenAI + Slack — it correctly classified 4 real CS emails (billing, technical, feature, general) and saved response drafts to Gmail's Drafts folder. Last verified: 2026-07-15.

Why save a draft instead of auto-sending

  • No matter how good the AI classification and draft are, a human should review for the first few weeks. A single misfired apology creates more trust damage than 90% accuracy is worth.
  • The draft lives in Gmail's Drafts folder, so the responder opens it in the original thread's reply interface, reviews and edits in 5 seconds, and clicks send once. The "AI wrote the draft" review flow is familiar to operators.
  • Once accuracy is proven, switching to auto-send is a one-line change: flip the Create Draft Reply node's operation from draft:create to message:send. You can also mix per category (e.g. auto-send general, draft everything else).

Technical note — why HTTP Request instead of the n8n OpenAI node

  • The n8n OpenAI node (typeVersion 1.7) has an issue where, under certain conditions, it constructs the request such that OpenAI returns the Welcome to the OpenAI API! intro text. No actual completion happens.
  • Attaching to the HTTP Request node via Authentication → Predefined Credential Type → OpenAI API returns a proper completion response using the same credential. The request payload is explicit, so debugging is easy.
  • The HTTP Request approach is essential when you need forced JSON responses like response_format: json_object.

Edge cases

  • Zero matching emails — if Gmail Get Many returns an empty result, downstream nodes don't run. The Slack post is silently skipped too.
  • AI fails to parse JSON — the Parse AI node is wrapped in try/catch and fills in fallback values (category: general, priority: normal). The draft is left as an empty string for the responder to write from scratch.
  • OpenAI error — the HTTP Request node ends the workflow in error. Check the Executions tab. In production, enable the node option Retry on Fail to absorb rate limits.
  • Missing Gmail label — if the cs-inbox label doesn't exist ahead of time, the search fails. In Gmail: sidebar → Create new label → cs-inbox.
  • Duplicate processing — after processing, the Mark as Read node flips the read state so the next run doesn't reprocess. To reprocess, mark unread manually in Gmail.
−68%
First response time
Automatic
Category + priority sorting
100% drafts
AI writes, human reviews + sends
<1,000 KRW/mo
GPT cost (100 tickets/day)
Urgent tickets don't get buried anymore. AI picks them out first.CS team lead

Your operation belongs
in here, too.

Tell us the most repetitive task you have. We'll map an automation scenario for it.