n8n Workflow Automation Fundamentals
1. n8n là gì?
n8n (n-eight-n) là workflow automation platform mã nguồn mở cho phép bạn kết nối các apps và services để tự động hóa công việc không cần code.
1.1 Tại sao chọn n8n?
| Feature | n8n | Zapier | Make (Integromat) |
|---|---|---|---|
| Pricing | Free self-hosted | $20+/month | $9+/month |
| Custom code | JavaScript, Python | Limited | Limited |
| Data privacy | Self-hosted option | Cloud only | Cloud only |
| Nodes | 400+ | 6000+ | 1500+ |
| Open source | ✅ Yes | ❌ No | ❌ No |
n8n phù hợp khi:
- Cần tự động hóa phức tạp với logic
- Quan tâm data privacy
- Muốn tùy biến cao
- Budget hạn chế
- Muốn integrate AI (OpenAI, Anthropic...)
1.2 Use Cases phổ biến
1n8n Automation Use Cases2├── Productivity & Office3│ ├── Auto-save Gmail attachments to Drive4│ ├── Sync calendar events to Notion5│ └── Daily digest email from multiple sources6├── Marketing & Sales7│ ├── Auto-nurture leads from forms8│ ├── Post to multiple social platforms9│ └── Track competitor prices10├── Data & Analytics11│ ├── Scrape websites to Google Sheets12│ ├── Daily reports from databases13│ └── Data sync between apps14└── AI Integration15 ├── Auto-reply emails with GPT-416 ├── Content generation pipelines17 └── AI-powered chatbots2. n8n Core Concepts
2.1 Workflow Anatomy
1Workflow = Nodes + Connections + Data Flow2 3Trigger → Action 1 → Action 2 → ... → Final ActionComponents:
- Trigger Node: Bắt đầu workflow (webhook, schedule, manual)
- Action Nodes: Thực hiện tasks (API calls, transformations)
- Connections: Luồng dữ liệu giữa nodes
- Expressions: Logic và data manipulation
2.2 Node Types
1. Trigger Nodes:
1// Schedule Trigger - Chạy định kỳ2- Cron: "0 9 * * 1-5" // 9am weekdays3- Interval: Every 1 hour45// Webhook Trigger - HTTP endpoint6- POST https://n8n.domain.com/webhook/abc1237- Nhận data từ forms, APIs, apps89// Manual Trigger - Chạy thủ công10- Test workflows11- One-time executions2. Data Nodes:
1// Google Sheets - Read/write spreadsheets2- Get rows, update cells3- Append new data45// Database - SQL operations6- MySQL, PostgreSQL, MongoDB7- SELECT, INSERT, UPDATE89// HTTP Request - Call any API10- GET, POST, PUT, DELETE11- Authentication: API key, OAuth3. Logic Nodes:
1// IF - Conditional branching2if ({{ $json.amount > 1000 }}) {3 → High value path4} else {5 → Low value path6}78// Switch - Multiple conditions9switch ({{ $json.category }}) {10 case "urgent": → Path A11 case "normal": → Path B12 default: → Path C13}1415// Merge - Combine data streams3. Hands-on: First Workflow
3.1 Gmail to Google Sheets
Objective: Tự động lưu emails quan trọng vào spreadsheet
Workflow:
1Gmail Trigger (new emails with label "Important")2→ Extract data (sender, subject, date, body)3→ Google Sheets (append row)4→ Gmail (mark as read)Implementation:
Step 1: Gmail Trigger
1// Gmail Trigger Node settings2Label: "Important"3Poll Interval: Every 5 minutes4Simple: false // Get full email dataStep 2: Set Node (Data extraction)
1{2 "sender": "={{ $json.from.text }}",3 "subject": "={{ $json.subject }}",4 "date": "={{ $json.date }}",5 "preview": "={{ $json.textPlain.slice(0, 200) }}",6 "url": "={{ $json.webLink }}"7}Step 3: Google Sheets
1Operation: Append2Spreadsheet: "Email Tracker"3Sheet: "Important Emails"4Columns: sender, subject, date, preview, urlStep 4: Gmail (mark as read)
1Operation: Update2Message ID: "={{ $node['Gmail Trigger'].json.id }}"3Label: Remove "UNREAD"4. Working with Data
4.1 Expressions & Variables
Access node data:
1// Current node data2{{ $json.fieldName }}34// Previous node data5{{ $node["Node Name"].json.field }}67// All items8{{ $items }}910// Item index11{{ $itemIndex }}Common operations:
1// String manipulation2{{ $json.email.toLowerCase() }}3{{ $json.name.split(' ')[0] }} // First name45// Math6{{ $json.price * 1.1 }} // +10% tax78// Date9{{ new Date($json.timestamp).toLocaleDateString() }}1011// Conditional12{{ $json.status === "active" ? "✅" : "❌" }}4.2 Data Transformation
Code Node (JavaScript):
1// Example: Calculate total from items2let total = 0;34for (const item of $input.all()) {5 total += item.json.amount;6}78return {9 totalAmount: total,10 itemCount: $input.all().length,11 avgAmount: total / $input.all().length12};5. Dự án: Personal Productivity Dashboard
5.1 Mô tả dự án
Tạo Daily Productivity Dashboard tự động tổng hợp:
- Gmail unread count
- Google Calendar events today
- Todoist tasks due
- GitHub commits yesterday
- Weather forecast
→ Gửi email summary mỗi sáng 8am
5.2 Workflow Design
1Schedule Trigger (8am daily)2├── Branch 1: Gmail → Count unread3├── Branch 2: Google Calendar → List events4├── Branch 3: Todoist → Get tasks5├── Branch 4: GitHub → Count commits6└── Branch 5: OpenWeather → Get forecast7 ↓8Merge all branches9 ↓10Format HTML email11 ↓12Send via Gmail5.3 Implementation
Schedule Trigger:
1Cron: "0 8 * * *" // 8am daily2Timezone: "Asia/Ho_Chi_Minh"Branch 1: Gmail unread count
1// Gmail Node2Operation: Search3Search: "is:unread"4Simple: true56// Code Node7return {8 unreadCount: $input.all().length9};Branch 2: Google Calendar
1// Google Calendar Node2Operation: Get Many3Calendar: primary4Time Min: {{ $today }}5Time Max: {{ $today + 1d }}6Max Results: 1078// Code Node - Format events9const events = $input.all().map(item => ({10 time: new Date(item.json.start.dateTime).toLocaleTimeString('vi-VN', {hour: '2-digit', minute: '2-digit'}),11 title: item.json.summary12}));1314return { todayEvents: events };Branch 3: Todoist
1// Todoist Node2Operation: Get All3Filter: "today | overdue"45// Count & categorize6const tasks = $input.all();7return {8 tasksToday: tasks.filter(t => t.json.due.string === "today").length,9 tasksOverdue: tasks.filter(t => t.json.is_recurring === false && new Date(t.json.due.date) < new Date()).length10};Branch 4: GitHub commits
1// HTTP Request Node2Method: GET3URL: https://api.github.com/users/YOUR_USERNAME/events4Authentication: Bearer Token56// Code Node - Count commits yesterday7const yesterday = new Date();8yesterday.setDate(yesterday.getDate() - 1);9const yesterdayStr = yesterday.toISOString().split('T')[0];1011const commits = $input.all().filter(event => 12 event.json.type === "PushEvent" && 13 event.json.created_at.startsWith(yesterdayStr)14);1516return { commitsYesterday: commits.length };Branch 5: Weather
1// OpenWeather Node2Operation: Current Weather3Location: "Ho Chi Minh City"45return {6 temp: Math.round($json.main.temp),7 description: $json.weather[0].description,8 humidity: $json.main.humidity9};Merge & Format Email:
1// Merge Node - Wait for all branches23// Code Node - Create HTML email4const data = $input.all().reduce((acc, item) => ({...acc, ...item.json}), {});56const html = `7<!DOCTYPE html>8<html>9<head>10 <style>11 body { font-family: Arial; line-height: 1.6; }12 .card { background: #f5f5f5; padding: 15px; margin: 10px 0; border-radius: 8px; }13 .number { font-size: 32px; font-weight: bold; color: #0066cc; }14 </style>15</head>16<body>17 <h1>�� Daily Dashboard - ${new Date().toLocaleDateString('vi-VN')}</h1>18 19 <div class="card">20 <h3>�� Email</h3>21 <div class="number">${data.unreadCount}</div>22 <p>Unread messages</p>23 </div>24 25 <div class="card">26 <h3>�� Calendar Today</h3>27 ${data.todayEvents.map(e => `<p>🕐 ${e.time} - ${e.title}</p>`).join('')}28 </div>29 30 <div class="card">31 <h3>✅ Tasks</h3>32 <p>${data.tasksToday} due today | ${data.tasksOverdue} overdue</p>33 </div>34 35 <div class="card">36 <h3>�� GitHub</h3>37 <p>${data.commitsYesterday} commits yesterday</p>38 </div>39 40 <div class="card">41 <h3>��️ Weather</h3>42 <div class="number">${data.temp}°C</div>43 <p>${data.description}</p>44 </div>45</body>46</html>47`;4849return { html };Send Email:
1// Gmail Node2Operation: Send3To: your-email@gmail.com4Subject: "Daily Dashboard - {{ new Date().toLocaleDateString('vi-VN') }}"5Email Type: HTML6Body: {{ $json.html }}6. Best Practices
6.1 Workflow Organization
1// ✅ DO2- Descriptive node names: "Filter high-value customers"3- Add Sticky Notes for documentation4- Group related workflows in folders5- Use consistent naming conventions67// ❌ DON'T8- Generic names: "HTTP Request 1", "IF 2"9- No documentation10- All workflows in root11- Inconsistent styles6.2 Error Handling
1// Error Trigger Node2Connected to: Any node that might fail34// Error handling workflow5Error Trigger6→ Code Node (log error details)7→ Send Telegram alert8→ Write to error log file6.3 Testing
11. Manual Trigger → Test with sample data22. Limit: 1 → Process only 1 item during testing33. Pin Data → Fix input data for consistent testing44. Execution History → Review past runs7. Deployment Options
7.1 n8n Cloud (Easiest)
1# Sign up at n8n.cloud2# Pricing: $20/month3# Pros: No setup, automatic updates4# Cons: Cost, less control7.2 Self-hosted (Recommended)
Docker Compose:
1version: '3'2 3services:4 n8n:5 image: n8nio/n8n6 restart: always7 ports:8 - "5678:5678"9 environment:10 - N8N_BASIC_AUTH_ACTIVE=true11 - N8N_BASIC_AUTH_USER=admin12 - N8N_BASIC_AUTH_PASSWORD=your-password13 - N8N_HOST=your-domain.com14 - N8N_PROTOCOL=https15 - WEBHOOK_URL=https://your-domain.com/16 volumes:17 - ~/.n8n:/home/node/.n8nRun:
1docker-compose up -d7.3 Railway.app (Free tier)
1# 1-click deploy2# Free $5 credit monthly3# Auto-scale4# Perfect for personal use8. Tài liệu tham khảo
Bài tập
- Bài 1: Tạo workflow tự động backup Google Docs sang Drive folder mỗi tuần
- Bài 2: Setup weather alert - gửi Telegram nếu có mưa
- Bài 3: Scrape tin tức từ VnExpress và post summary lên Notion
- Bài 4: Implement Daily Productivity Dashboard
- Bài 5: Auto-tag Gmail emails by sender domain
