Building Real AI Agents with n8n (Not Toy Examples)
Toy examples are great for learning. But real businesses need agents that remember conversations, understand context, and handle complexity. Let's build one.
The Email Assistant with Memory
This agent will:
- Remember every conversation with each customer
- Give contextual responses based on history
- Never ask for information you already provided
- Handle complex multi-turn conversations
Time to build: 45 minutes
Time saved: 10+ hours/week
Difficulty: Intermediate
Prerequisites
You need:
- n8n account (cloud or self-hosted)
- OpenAI API key
- Gmail connected (see our n8n setup guide)
- Google Sheets for memory storage
Why Memory Matters
Without Memory (Basic Agent)
Customer: "What are your business hours?"
Agent: "We're open 9-5 Monday-Friday."
Customer (2 days later): "I tried calling at 4pm on Tuesday but no answer."
Agent: "What are your business hours?"
Customer: 😤 (I literally just asked this 2 days ago!)
With Memory (Smart Agent)
Customer: "What are your business hours?"
Agent: "We're open 9-5 Monday-Friday."
Customer (2 days later): "I tried calling at 4pm on Tuesday but no answer."
Agent: "I'm sorry you couldn't reach us Tuesday at 4pm. That's definitely within our 9-5 hours. Let me check what might have happened and have someone call you back. When's a good time?"
Customer: 😊 (They remembered our previous conversation!)
Architecture Overview
Here's how our memory system works:
Email Arrives
↓
1. Check Google Sheets for past conversations with this customer
↓
2. Load conversation history (last 5 interactions)
↓
3. Send: [History] + [New Email] → AI
↓
4. AI generates contextual response
↓
5. Send response to customer
↓
6. Save [Customer Email] + [AI Response] to Google Sheets
Simple concept. Powerful results.
Step 1: Create Memory Database (10 Min)
Set Up Google Sheet
- Create new Google Sheet
- Name it: "Email Conversations"
- Add these columns:
| A | B | C | D | E | |---|---|---|---|---| | Customer Email | Date | Customer Message | AI Response | Thread ID |
Connect Google Sheets to n8n
- In n8n, add "Google Sheets" node
- Click "Create New Credential"
- Choose "OAuth2"
- Sign in with Google
- Grant permissions
- Save credential
Test Connection
Add a test row manually to verify:
- Customer Email:
test@example.com - Date: Today's date
- Customer Message:
Test message - AI Response:
Test response - Thread ID:
thread_123
In n8n, test reading this data.
Step 2: Build the Workflow
Node 1: Gmail Trigger
Set up the trigger:
- Event:
message.received - Label:
INBOX - Trigger on:
messageAdded
Node 2: Extract Email Data
Add "Set" node to clean up the data:
Field Mapping:
{
"customer_email": "={{$json.from}}",
"customer_name": "={{$json.from.split('<')[0].trim()}}",
"subject": "={{$json.subject}}",
"message": "={{$json.text}}",
"thread_id": "={{$json.threadId}}",
"received_date": "={{$now.toISO()}}"
}
Why clean the data? Makes it easier to work with in next steps.
Node 3: Search Past Conversations
Add "Google Sheets" node:
- Operation:
Lookup - Document:
Email Conversations - Sheet:
Sheet1 - Lookup Column:
A(Customer Email column) - Lookup Value:
={{$('Set').item.json.customer_email}} - Return all matches:
Yes
This finds all past emails with this customer.
Important: Enable "Return All Matches" to get full history, not just the first match.
Node 4: Build Conversation History
Add "Code" node (this is where n8n shines):
Language: JavaScript
// Get past conversations
const pastConversations = $input.all();
const currentEmail = $('Set').item.json;
// Build history string
let history = "";
if (pastConversations.length > 0) {
history = "Previous conversations with this customer:\n\n";
// Get last 5 conversations only (to save tokens)
const recent = pastConversations.slice(-5);
recent.forEach((conv, index) => {
const convData = conv.json;
history += `Conversation ${index + 1} (${convData.Date}):\n`;
history += `Customer: ${convData["Customer Message"]}\n`;
history += `You replied: ${convData["AI Response"]}\n\n`;
});
history += `Total past interactions: ${pastConversations.length}\n`;
} else {
history = "This is a new customer (no previous conversations).\n";
}
// Output for next node
return [{
json: {
history: history,
current_message: currentEmail.message,
customer_email: currentEmail.customer_email,
customer_name: currentEmail.customer_name,
subject: currentEmail.subject,
thread_id: currentEmail.thread_id,
has_history: pastConversations.length > 0
}
}];
What this does:
- Takes last 5 conversations (to save AI tokens and stay relevant)
- Formats them nicely for AI to understand
- Adds context about whether this is a new or returning customer
Node 5: Generate Contextual Response
Add "OpenAI Chat Model" node:
Model: gpt-4o (use the good model for customer service)
System Message:
You are a helpful customer service assistant for [YOUR COMPANY NAME].
You have access to past conversations with this customer.
Use this context to provide personalized, relevant responses.
Guidelines:
- Reference past conversations when relevant ("As we discussed on [date]...")
- Never ask for information they already provided
- Be warm and recognize them as a returning customer if they have history
- If they're new, welcome them warmly
- Keep responses under 200 words
- Be professional but friendly
- End with a clear call-to-action or question
Context about this customer:
{{$json.has_history ? "Returning customer - see conversation history below" : "New customer - first interaction"}}
User Message:
{{$json.history}}
Current email from {{$json.customer_name}}:
Subject: {{$json.subject}}
Message: {{$json.current_message}}
Write a helpful, contextual response:
Advanced Options:
- Temperature:
0.7(balanced between creative and consistent) - Max Tokens:
500
Node 6: Send the Response
Add "Gmail" node:
Operation: Send an Email (or Create a Draft if you want to review first)
Configure:
- To:
={{$('Code').item.json.customer_email}} - Subject:
Re: {{$('Code').item.json.subject}} - Message:
={{$json.choices[0].message.content}}
Node 7: Save to Memory
Add "Google Sheets" node:
Operation: Append
Document: Email Conversations
Sheet: Sheet1
Data to append:
{
"Customer Email": "={{$('Code').item.json.customer_email}}",
"Date": "={{$now.toISO()}}",
"Customer Message": "={{$('Code').item.json.current_message}}",
"AI Response": "={{$('OpenAI Chat Model').item.json.choices[0].message.content}}",
"Thread ID": "={{$('Code').item.json.thread_id}}"
}
Critical: This must be the LAST node in your workflow. Otherwise, the response isn't saved and memory doesn't work.
Step 3: Test the Memory System
Test 1: First Interaction
- Send an email: "What are your business hours?"
- Check the AI response
- Verify it's saved to Google Sheets
Expected: Generic but helpful response (no history to reference).
Test 2: Second Interaction (Memory Kicks In)
- Send another email from the same address: "Can I schedule a meeting next Tuesday?"
- AI should reference your previous question
- Check Google Sheets - should have 2 rows now
Expected: Response mentions your previous inquiry about business hours.
Test 3: Complex History
- Have 3-4 email exchanges with the agent
- Each time, check if it references previous conversations
- Verify Google Sheets is logging everything
Expected: By conversation 4-5, agent should have rich context and give highly personalized responses.
Advanced Features to Add
Feature 1: Sentiment Tracking
Track if customer is getting frustrated:
Add to Code node:
// Analyze sentiment trend
const sentiments = pastConversations.map(conv => {
const text = conv.json["Customer Message"].toLowerCase();
if (text.includes('frustrated') || text.includes('angry') || text.includes('disappointed')) {
return 'negative';
} else if (text.includes('thank') || text.includes('great') || text.includes('appreciate')) {
return 'positive';
}
return 'neutral';
});
// If last 2 messages are negative, escalate
const recentNegative = sentiments.slice(-2).filter(s => s === 'negative').length === 2;
// Add to output
return [{
json: {
...existing_data,
sentiment_alert: recentNegative,
sentiment_history: sentiments
}
}];
Use this to:
- Alert human team if sentiment trends negative
- Adjust AI tone to be more empathetic
- Offer escalation to human sooner
Feature 2: Smart Context Window
Instead of always using last 5 conversations, use the most RELEVANT ones:
Replace history building logic:
// Instead of last 5, find most relevant to current question
const currentQuestion = currentEmail.message.toLowerCase();
// Score each past conversation for relevance
const scored = pastConversations.map(conv => {
const pastMessage = conv.json["Customer Message"].toLowerCase();
// Simple keyword matching (upgrade to embeddings for better results)
const keywords = currentQuestion.split(' ').filter(w => w.length > 4);
const relevance = keywords.filter(kw => pastMessage.includes(kw)).length;
return {
conversation: conv,
relevance: relevance,
date: new Date(conv.json.Date)
};
});
// Sort by relevance, then date
scored.sort((a, b) => {
if (a.relevance !== b.relevance) return b.relevance - a.relevance;
return b.date - a.date;
});
// Take top 5 most relevant
const relevant = scored.slice(0, 5).map(s => s.conversation);
Result: AI sees conversations actually related to the current question, not just the most recent ones.
Feature 3: Auto-Escalation
Some situations need human help:
Add IF node after sentiment analysis:
// Conditions that trigger escalation
const needsHuman =
$json.sentiment_alert || // Customer is frustrated
$json.current_message.toLowerCase().includes('speak to manager') ||
$json.current_message.toLowerCase().includes('cancel') ||
pastConversations.length > 5; // Too many back-and-forth emails
return [{ json: { escalate: needsHuman } }];
Then route:
- If escalate = true → Send to human via Slack/Email
- If escalate = false → AI handles it
Cost Analysis
Per conversation with memory:
- Google Sheets: Free (< 1M operations)
- OpenAI GPT-4o: ~$0.02 per email (with history context)
- n8n operations: 5 per email
Monthly costs (100 emails/day):
- Google Sheets: $0
- OpenAI: $60/month
- n8n Cloud: $20/month
- Total: $80/month
Value delivered: 40 hours/month saved = $2,000/month (at $50/hour)
ROI: 2,400%
Production Considerations
1. Data Privacy
Storing customer emails in Google Sheets?
Better approach for production:
- Use Airtable (better permissions)
- Use Postgres database (most secure)
- Use Supabase (easy + secure)
Add encryption for sensitive data:
const crypto = require('crypto');
const encrypted = crypto.createCipher('aes-256-cbc', process.env.ENCRYPTION_KEY)
.update(sensitiveData, 'utf8', 'hex');
2. Scaling Past Google Sheets
Google Sheets works up to ~10,000 conversations.
When to upgrade:
- 10,000+ conversations: Use Postgres
- Need fast lookups: Add vector database (Pinecone) for semantic search
- Multiple agents: Use shared database with proper indexing
3. Error Handling
Always add fallback logic:
// If memory lookup fails
if (!pastConversations || pastConversations.length === 0) {
history = "Unable to load conversation history. Treating as new customer.";
// Continue anyway - don't block on memory failure
}
4. Rate Limiting
OpenAI has rate limits. Add queue system:
- Add all incoming emails to queue (Google Sheets or Redis)
- Process queue at controlled rate (5 per minute)
- Prevents hitting API limits during email spikes
Real Results from Production Use
E-commerce company using this exact system:
- Before: 200 support emails/day, 4-hour average response time
- After: AI handles 140/day (70%), humans handle 60/day (30%)
- Response time: 2 minutes average
- Customer satisfaction: +23%
- Support cost: -$4,000/month
The memory system was the difference. Without it, AI made customers repeat themselves. With it, conversations felt natural.
Next Steps
You now have a production-ready AI agent with memory.
Week 1: Run in draft mode, review all responses
Week 2: Auto-send for simple inquiries, human review for complex ones
Week 3: Add sentiment tracking and auto-escalation
Week 4: Optimize based on real conversations
Want to go even deeper? Learn about:
- Relevance AI for pre-built agent systems
- Lindy AI for natural language agent creation
- MCP Servers for next-gen agent architectures
Need help implementing this system? Contact us for custom agent development and consulting.


