How to Build Your First AI Automation: Email Triage in n8n
Build an n8n workflow that reads new Gmail, asks a small OpenAI model for JSON, and appends each result to a Google Sheet. No automation experience needed.

By the end of this, every new email in your inbox becomes a row in a Google Sheet: who sent it, what company they're from, what they want, how urgent it is, and a one-line summary. It's four nodes in n8n, and the model costs a fraction of a cent per email.
The shape is simple. A trigger notices something happened. An AI step turns messy text into tidy fields. An action writes those fields somewhere useful. Once you've built it for email, the same shape works for routing tickets, scoring leads, and sorting documents.
What you will build
The workflow watches a Gmail inbox. When a new email arrives, it sends the subject and body to a small OpenAI model. The model sends back JSON, a simple structured format, with the sender's name, company, intent (sales, support, recruiting, spam), urgency (low, medium, high), and a one-sentence summary. n8n adds that as a row in a Google Sheet. That's a starter CRM for incoming leads, built in one sitting.
What you need before you start
Three accounts. The OpenAI one is the only one that needs money up front.
- An n8n cloud account at n8n.io: a 14-day free trial with no credit card, then the Starter plan at 20 dollars a month billed annually or 24 billed monthly as of September 2026. Or self-host the free Community Edition instead.
- A Google account with Gmail and Sheets access
- An OpenAI API account with prepaid credit. New API accounts use prepaid billing, and the minimum purchase is 5 dollars, so add a payment method and buy the minimum before step 2. This tutorial uses
gpt-6-luna, which OpenAI's pricing page lists at 0.10 dollars per million input tokens and 0.50 dollars per million output tokens as of September 2026. A typical email is well under a cent.
If you want a path with no payment at all, run n8n self-hosted on your laptop, and swap OpenAI for a provider with a free API tier: Gemini's Flash models or Groq, both free within rate limits as of September 2026. Google says free-tier content may be used to improve its products, so don't send real customer email through it. Everything else in this guide stays the same.
OpenAI renames and retires its small models often. If gpt-6-luna has been replaced by the time you read this, use whichever model the models page recommends for high-volume work, as long as it supports structured outputs.
Step 1: Set up the trigger
Sign in to n8n cloud and create a new workflow. Add a Gmail Trigger node and connect your Google account when it asks you to sign in (that's the OAuth flow). Set the trigger to "On Message Received" and have it check every minute. Filter to one label, like inbox or a custom automate-me label, so you can test without flooding your sheet with every email you already have.
Click "Listen for Test Event" and send yourself an email from another account. The node should turn green, with the subject, body, and sender showing in the right panel. If it doesn't, check two things. First, the Gmail permissions: sign in again and make sure you grant the access it asks for. Second, the label filter: the name has to match exactly.
Step 2: Send the email content to an LLM
Add an OpenAI node after the Gmail trigger. Choose the Generate a Chat Completion text operation, pick model gpt-6-luna, and turn on the Output Content as JSON option.
Leave temperature unset. Current OpenAI models are reasoning models, and their model guidance says to remove temperature unless reasoning effort is none.
The system message, the standing instructions the model gets before each email, goes:
You are a strict JSON extraction service. Given an email, return ONLY valid JSON matching this schema:
{
"sender_name": "string",
"company": "string or null",
"intent": "sales | support | recruiting | spam | other",
"urgency": "low | medium | high",
"summary": "one sentence summary"
}
Do not include any text outside the JSON.
The user message is the email itself, pulled from the trigger's output:
Subject: {{ $json.subject }}
From: {{ $json.from.value[0].address }}
Body: {{ $json.text }}
Run the node. The output panel should show the five fields under the message content. If you get a paragraph instead of JSON, check that Output Content as JSON is on, then add the phrase "ONLY JSON, no prose" to the system message.
Step 3: Parse the JSON response
Add a Code node after the OpenAI node and replace the default JavaScript with:
const content = $input.first().json.message?.content;
const fallback = { sender_name: 'unknown', company: null, intent: 'other', urgency: 'low', summary: 'JSON parse failed' };
let parsed;
try {
parsed = typeof content === 'string' ? JSON.parse(content) : content;
if (!parsed || typeof parsed !== 'object') parsed = fallback;
} catch (e) {
parsed = fallback;
}
return [{ json: parsed }];
The code handles the reply whether it arrives as text or as JSON n8n already unpacked, since the JSON option can give you either. If your node version puts the reply somewhere else, click the field in the OpenAI node's output panel and copy its path into the first line.
This is the most important node in the workflow. Now and then a model sends back broken JSON. Without the try/catch, which tells the code what to do when something fails, the whole workflow stops. With it, a bad reply writes a row marked "JSON parse failed" that you can look at later.
Always wrap the step that reads a model's JSON in a try/catch with fallback values. Models sometimes reply in prose when you asked for JSON, or leave out a field. Plan for both.
Step 4: Write the row to Google Sheets
Create a new sheet called email-triage with these columns: received_at, sender_name, company, intent, urgency, summary, original_subject.
Add a Google Sheets node and connect your Google account. Set the operation to "Append Row" and fill each column from the earlier nodes: received_at from the Gmail trigger's date, sender_name through summary from the Code node, and original_subject from the Gmail trigger.
Run the whole workflow with a test email. A new row should show up in your sheet within seconds.
Step 5: Activate and test
Click the Active toggle at the top right of the workflow. Send three different test emails: a sales inquiry, a support question, and an obvious recruiter pitch. Check your sheet after a minute. All three should be there, each tagged with the right intent.
That's a working AI automation in four nodes. At OpenAI's published price for gpt-6-luna, a 1,000-token email with a 150-token reply costs about 0.0002 dollars before reasoning tokens, which are billed as output.
What to do when it breaks
It will break at some point. Here are three ways it can go wrong and how to fix each.
The model replies in prose instead of JSON. Repeat the JSON-only rule in the user message. If it still happens, switch the OpenAI node to the Generate a Model Response operation, set Output Format to JSON Schema, and paste in the schema from the system message. With Structured Outputs, the model can only reply in that shape. It isn't just asked to.
The model makes up a sender name or company. Usually the email didn't contain it, and the prompt asked for it anyway. Let the field be empty (null) in the schema, and tell the model to return null when the value isn't there.
Google Sheets throws a quota error. Google's published limit is 60 write requests per minute per user. Personal use won't come close. For higher volume, write to Airtable or a Postgres table instead.
The pattern, generalized
Trigger, AI step, action. That shape is behind most useful AI automations. A few that fit the same template:
- Trigger: new Slack message in a channel. AI: classify whether this needs the on-call engineer. Action: page on-call if yes.
- Trigger: new Stripe charge. AI: write a personalized thank-you email referencing the customer's plan and history. Action: send via SendGrid.
- Trigger: new podcast episode in an RSS feed. AI: summarize the episode and extract three key claims. Action: post to a Notion database.
- Trigger: new GitHub issue. AI: classify priority and tag the right component. Action: update the issue with the labels.
Each is the same four nodes with different apps plugged in. Once you've built one, the rest are mostly a new trigger and a new prompt.
What to do next
Three ways to extend it:
- Add a Filter node before the OpenAI call to skip newsletters and automated emails. That saves money and cuts noise.
- Add a Slack node next to the Sheets node that pings you right away when an email is tagged high urgency.
- Swap the Google Sheet for an Airtable base, add columns to track follow-ups, and you have a small working CRM.
Keep costs in check while you do. Prepaid billing already stops requests when your credit runs out, but turn off auto-reload in OpenAI's billing settings until you've watched a week of real traffic, since the help article says it's on by default. If you later want to compare n8n with Make or Zapier, the automation playbook prices the same workflow on each.
The model was one node out of four. Most of the work in any automation is the rest: a trigger that fires at the right time, a prompt that gives the same shape of answer every time, and a destination someone actually looks at. For a bigger build on the same pattern, try the n8n lead generation workflow.