Example: Scheduled Daily Report Workflow¶
Create a workflow that runs daily and sends automated email reports.
What You'll Build¶
A scheduled workflow that:
- Runs every day at 9 AM
- Fetches data from an API
- Formats the data into a readable report
- Sends email report to team
Time Required: 15 minutes Difficulty: Beginner Prerequisites: Email credentials configured in n8n
Problem Statement¶
Your team needs a daily metrics report delivered to their inbox every morning at 9 AM. The report should include: - Total users - Active sessions - Revenue - Top performing products
Currently, someone manually generates this report each morning, taking 30 minutes of their time.
Business Impact: - Time Saved: 30 minutes/day = 10 hours/month - Consistency: No missed reports - Timeliness: Delivered exactly at 9 AM - Automation: Zero manual effort
Solution Architecture¶
[Schedule Trigger]
9 AM Daily
ā
[HTTP Request]
Fetch Metrics API
ā
[Code Node]
Format Report
ā
[Send Email]
Team Distribution
Workflow Characteristics: - Trigger: Schedule (Cron: 0 9 * * *) - Nodes: 4 (Schedule, HTTP Request, Code, Email) - Frequency: Daily at 9:00 AM - Timezone: Configurable
Step-by-Step Tutorial¶
Step 1: Create the Scheduled Workflow¶
You: "Create a daily report workflow that runs at 9 AM, fetches data from https://api.example.com/metrics, and emails the results to team@company.com"
Claude: I'll create a scheduled workflow for your daily report.
[MCP tool call: create_workflow]
{
"instance": "production",
"name": "Daily Metrics Report",
"nodes": [
{
"id": "schedule_1",
"name": "Schedule Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.1,
"position": [250, 300],
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "0 9 * * *"
}
]
},
"timezone": "America/New_York"
}
},
{
"id": "http_1",
"name": "Fetch Metrics",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.1,
"position": [450, 300],
"parameters": {
"url": "https://api.example.com/metrics",
"authentication": "none",
"options": {
"timeout": 10000
}
}
},
{
"id": "code_1",
"name": "Format Report",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [650, 300],
"parameters": {
"mode": "runOnceForAllItems",
"jsCode": "const metrics = $input.all()[0].json;\n\nconst today = new Date().toLocaleDateString('en-US', {\n weekday: 'long',\n year: 'numeric',\n month: 'long',\n day: 'numeric'\n});\n\nconst report = `\nš Daily Metrics Report - ${today}\n${'='.repeat(60)}\n\nš„ USERS\n Total Users: ${metrics.users.toLocaleString()}\n New Today: ${metrics.newUsers.toLocaleString()}\n Active Sessions: ${metrics.activeSessions.toLocaleString()}\n\nš° REVENUE\n Today's Revenue: $${metrics.revenue.toLocaleString('en-US', { minimumFractionDigits: 2 })}\n Monthly Total: $${metrics.monthlyRevenue.toLocaleString('en-US', { minimumFractionDigits: 2 })}\n Target Progress: ${((metrics.revenue / metrics.target) * 100).toFixed(1)}%\n\nš TOP PRODUCTS\n${metrics.topProducts.map((p, i) => \n ` ${i + 1}. ${p.name.padEnd(30)} $${p.sales.toLocaleString()}`\n).join('\\n')}\n\n${'='.repeat(60)}\nGenerated: ${new Date().toISOString()}\n`;\n\nreturn [{ json: { report, subject: `Daily Metrics - ${today}` } }];"
}
},
{
"id": "email_1",
"name": "Send Email",
"type": "n8n-nodes-base.emailSend",
"typeVersion": 2,
"position": [850, 300],
"parameters": {
"fromEmail": "reports@company.com",
"toEmail": "team@company.com",
"subject": "={{ $json.subject }}",
"emailType": "text",
"message": "={{ $json.report }}"
},
"credentials": {
"smtp": {
"id": "1",
"name": "Company SMTP"
}
}
}
],
"connections": {
"Schedule Trigger": {
"main": [[{ "node": "Fetch Metrics", "type": "main", "index": 0 }]]
},
"Fetch Metrics": {
"main": [[{ "node": "Format Report", "type": "main", "index": 0 }]]
},
"Format Report": {
"main": [[{ "node": "Send Email", "type": "main", "index": 0 }]]
}
},
"active": false
}
ā
Workflow "Daily Metrics Report" created successfully
Details:
- ID: 456
- Schedule: Daily at 9:00 AM EST
- Status: Inactive (test before activating)
- Nodes: 4 (Schedule, HTTP, Code, Email)
IMPORTANT: Test manually before activating!
Step 2: Manual Testing (Required Before Activation)¶
Since this workflow has a schedule trigger, you cannot execute it via the MCP server API. Instead, test in the n8n UI:
You: "How do I test this workflow before activating it?"
Claude: Great question! Here's how to test schedule-based workflows:
**Method 1: Manual Test in n8n UI (Recommended)**
1. Open n8n UI: https://your-n8n.cloud
2. Navigate to workflow "Daily Metrics Report"
3. Click "Test Workflow" button (top right)
4. Click "Execute Workflow"
5. Review results in execution panel
**Method 2: Temporarily Add Manual Trigger**
Ask me to add a manual trigger for testing:
"Add a manual trigger to workflow 456 for testing purposes"
**Method 3: Change Schedule to Run Soon**
Temporarily change schedule to run in 5 minutes:
"Update workflow 456 schedule to run at [current_time + 5 minutes]"
I recommend Method 1 for quickest testing.
Testing in n8n UI:¶
- Open Workflow: Navigate to workflow in n8n UI
- Click "Test Workflow": Top-right button
- Execute: Click "Execute Workflow"
- Review Output: Check each node's output:
- Schedule Trigger: ā Triggered
- Fetch Metrics: ā API response received
- Format Report: ā Report formatted
- Send Email: ā Email sent
Expected Email Output:
From: reports@company.com
To: team@company.com
Subject: Daily Metrics - Wednesday, January 15, 2025
š Daily Metrics Report - Wednesday, January 15, 2025
============================================================
š„ USERS
Total Users: 15,432
New Today: 127
Active Sessions: 1,245
š° REVENUE
Today's Revenue: $12,450.75
Monthly Total: $187,234.50
Target Progress: 93.6%
š TOP PRODUCTS
1. Premium Plan $5,200
2. Starter Plan $3,100
3. Enterprise License $2,800
============================================================
Generated: 2025-01-15T09:00:23.456Z
Step 3: Activate for Production¶
After successful testing:
You: "The test worked perfectly! Activate workflow 456 in production."
Claude: Excellent! I'll activate the daily report workflow.
[MCP tool call: activate_workflow]
{
"instance": "production",
"id": "456"
}
ā
Workflow activated successfully
Your Daily Metrics Report will now run automatically every day at 9:00 AM EST.
**Next Execution:** Tomorrow at 09:00:00 EST
**Recipients:** team@company.com
**Status:** Active ā
Would you like me to:
1. Set up execution monitoring?
2. Add error notifications?
3. Create a backup recipient list?
Customization Options¶
Change Schedule Time¶
Update to different time:
You: "Change workflow 456 to run at 6 AM instead of 9 AM"
Claude: I'll update the schedule to 6:00 AM.
[Updates cron expression from "0 9 * * *" to "0 6 * * *"]
ā
Schedule updated to 6:00 AM daily
Change Timezone¶
You: "Update workflow 456 timezone to Pacific Time (PT)"
Claude: I'll change the timezone to America/Los_Angeles (PT).
[Updates timezone parameter]
ā
Timezone changed to Pacific Time
Next execution: Tomorrow at 09:00:00 PST
Add Multiple Recipients¶
You: "Add sarah@company.com and john@company.com to the recipient list"
Claude: I'll update the email recipients.
[Updates toEmail parameter to "team@company.com, sarah@company.com, john@company.com"]
ā
Email recipients updated
Now sending to: team@company.com, sarah@company.com, john@company.com
Schedule Examples¶
Weekdays Only (Monday-Friday)¶
Twice Daily¶
Weekly (Monday Only)¶
Monthly (1st of Month)¶
Every Hour¶
Common Pitfalls¶
Issue 1: Wrong Timezone¶
Symptom: Report arrives at unexpected time
Solution:
You: "Check what timezone workflow 456 is using"
Claude: [Gets workflow details]
Current timezone: UTC
9:00 AM UTC = 4:00 AM EST
Would you like me to change it to America/New_York (EST)?
Fix: Always specify timezone explicitly
Issue 2: API Timeout¶
Symptom: Workflow fails with timeout error
Cause: API response takes >10 seconds
Solution:
{
"name": "Fetch Metrics",
"parameters": {
"url": "https://api.example.com/metrics",
"options": {
"timeout": 30000 // Increase to 30 seconds
}
}
}
Issue 3: Email Not Sending¶
Symptom: Execution succeeds but no email received
Checklist: 1. ā SMTP credentials configured? 2. ā Recipient email correct? 3. ā Check spam folder 4. ā SMTP server accessible?
Debug:
You: "Why isn't workflow 456 sending emails? Show me the latest execution."
Claude: [Gets execution details]
Execution shows:
- HTTP Request: ā
Success
- Format Report: ā
Success
- Send Email: ā Failed - "Authentication failed"
Issue: SMTP credentials invalid or expired.
Fix:
1. Open n8n UI ā Settings ā Credentials
2. Test SMTP credential
3. Update if needed
4. Retry workflow execution
Advanced Features¶
Add Error Handling¶
You: "Add error handling to workflow 456 that sends a Slack alert if the API fails"
Claude: I'll add error handling with Slack notifications.
[Adds error trigger node and Slack notification]
ā
Error handling added
- On HTTP Request failure ā Send Slack alert to #ops-alerts
- Include error details and timestamp
- Workflow continues to attempt tomorrow
HTML Email Format¶
Replace plain text with HTML:
{
"name": "Send Email",
"parameters": {
"emailType": "html",
"message": `
<html>
<body style="font-family: Arial, sans-serif;">
<h2>š Daily Metrics Report</h2>
<table style="border-collapse: collapse;">
<tr>
<td><strong>Total Users:</strong></td>
<td>{{ $json.users }}</td>
</tr>
<tr>
<td><strong>Revenue:</strong></td>
<td>$</ $json.revenue }}</td>
</tr>
</table>
</body>
</html>
`
}
}
Add Charts/Graphs¶
Use external chart service:
{
"name": "Generate Chart",
"type": "n8n-nodes-base.httpRequest",
"parameters": {
"url": "https://quickchart.io/chart",
"method": "POST",
"sendBody": true,
"bodyParameters": {
"chart": {
"type": "line",
"data": {
"labels": ["Mon", "Tue", "Wed", "Thu", "Fri"],
"datasets": [{
"label": "Revenue",
"data": "={{ $json.dailyRevenue }}"
}]
}
}
}
}
}
Monitoring and Alerts¶
Track Execution Success¶
You: "Show me execution history for workflow 456 over the last 7 days"
Claude: I'll retrieve the execution history.
[MCP tool call: list_executions with time filter]
Last 7 days execution summary:
- Total executions: 7
- Successful: 6 ā
- Failed: 1 ā
- Average duration: 2.3 seconds
Failed execution:
- Date: Jan 12, 2025
- Error: API timeout
- Status: Resolved (API was temporarily down)
Set Up Success Monitoring¶
You: "Add a check that alerts me if the workflow hasn't run in 25 hours"
Claude: I'll create a monitoring workflow that checks execution status.
[Creates separate monitoring workflow]
ā
Monitoring workflow created
- Checks every hour if Daily Metrics Report ran in last 25 hours
- Sends alert if missing
- Notifies: your-email@company.com
Complete Workflow Definition¶
{
"name": "Daily Metrics Report",
"nodes": [
{
"id": "schedule_1",
"name": "Schedule Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"typeVersion": 1.1,
"position": [250, 300],
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "0 9 * * *"
}
]
},
"timezone": "America/New_York"
}
},
{
"id": "http_1",
"name": "Fetch Metrics",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 4.1,
"position": [450, 300],
"parameters": {
"url": "https://api.example.com/metrics",
"authentication": "none",
"requestMethod": "GET",
"options": {
"timeout": 10000,
"retry": {
"enabled": true,
"maxRetries": 3,
"waitBetweenRetries": 1000
}
}
}
},
{
"id": "code_1",
"name": "Format Report",
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [650, 300],
"parameters": {
"mode": "runOnceForAllItems",
"jsCode": "// Full formatting code here"
}
},
{
"id": "email_1",
"name": "Send Email",
"type": "n8n-nodes-base.emailSend",
"typeVersion": 2,
"position": [850, 300],
"parameters": {
"fromEmail": "reports@company.com",
"toEmail": "team@company.com",
"subject": "={{ $json.subject }}",
"emailType": "text",
"message": "={{ $json.report }}"
},
"credentials": {
"smtp": {
"id": "1",
"name": "Company SMTP"
}
}
}
],
"connections": {
"Schedule Trigger": {
"main": [[{ "node": "Fetch Metrics", "type": "main", "index": 0 }]]
},
"Fetch Metrics": {
"main": [[{ "node": "Format Report", "type": "main", "index": 0 }]]
},
"Format Report": {
"main": [[{ "node": "Send Email", "type": "main", "index": 0 }]]
}
},
"active": true,
"settings": {
"saveExecutionProgress": true,
"saveManualExecutions": true,
"saveDataErrorExecution": "all",
"saveDataSuccessExecution": "all",
"executionTimeout": 60,
"timezone": "America/New_York"
},
"tags": [
{ "name": "daily" },
{ "name": "reports" },
{ "name": "automated" }
]
}
Key Takeaways¶
ā Learned: - Create scheduled workflows with cron expressions - Test schedule-based workflows before activation - Format data into readable reports - Send automated emails
ā Best Practices: - Always test manually in n8n UI first - Specify timezone explicitly - Add error handling for API calls - Monitor execution history
ā Production Ready: - Configure retry logic for API calls - Set up failure alerts - Use HTML formatting for better readability - Add backup recipients
Estimated Reading Time: 12 minutes Setup Time: 15 minutes Total Time: 27 minutes