This workflow corresponds to n8n.io template #16612 — we link there as the canonical source.
This workflow follows the Agent → Gmail recipe pattern — see all workflows that pair these two integrations.
The workflow JSON
Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →
{
"id": "XKjbEok8gd4827Ki",
"name": "Weekly Client Report Generator",
"tags": [],
"nodes": [
{
"id": "7fab9d22-a884-4911-b7c5-16d34f972703",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-592,
-64
],
"parameters": {
"color": 2,
"width": 656,
"height": 880,
"content": "# Weekly Client Report Generator\n\nEvery Friday morning, pulls this week's data from Google Sheets and sends each client a professional, narrative-style weekly update not a bullet list of tasks, but a clear, confident summary a senior account manager would write.\n\n\n## How it works\n\n1. **Every Friday at 9 AM** the schedule trigger fires.\n2. **Fetch Weekly Data** reads all active client rows from your Google Sheet.\n3. **Normalize Sheet Data** maps the row columns into a consistent shape and builds the week label automatically.\n4. **Claude** writes a 3-4 paragraph narrative report with an HTML and plain-text version; professional prose, not a task dump.\n5. **Send Report Email** delivers the HTML email directly to the client's email address on record.\n\n\n## Google Sheet setup\n\nCreate a sheet with these exact column headers:\n\n\n| Column | Required | Notes |\n| :--- | :---: | :--- |\n| Client Name | Yes | Recipient name |\n| Client Email | Yes | Where the report is sent |\n| Project Name | No | Shown in report heading |\n| Sender Name | No | Your name / team name |\n| Sender Email | No | Optional reply-to |\n| Status | No | Set to \"paused\" or \"inactive\" to skip |\n| Tasks Completed | No | Comma-separated or paragraph |\n| Tasks In Progress | No | Optional |\n| Blockers | No | Optional |\n| Next Week Plan | No | Optional |\n| Metric: [Name] | No | Add as many as you like (e.g., Metric: Sessions) |\n\n\nFor metrics, add any column starting with \"Metric:\" e.g. \"Metric: Revenue\", \"Metric: Tasks Closed\", \"Metric: Uptime\". All matching columns are included automatically.\n\n\n## Setup steps\n\n- [ ] Create a Google Sheet with the columns above and paste the Sheet ID into the Fetch Weekly Data node\n- [ ] Connect Google Sheets credentials\n- [ ] Add Anthropic credentials to the Anthropic Chat Model node\n- [ ] Connect Gmail credentials for sending reports\n- [ ] Customize the Claude system prompt tone to match your agency's voice"
},
"typeVersion": 1
},
{
"id": "15ed4ca5-98b6-4ff8-b896-b4e9cf850ab6",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
96,
-64
],
"parameters": {
"color": 7,
"width": 672,
"height": 624,
"content": "## Fetch and normalize\n\nSchedule fires every Friday. Reads all active client rows and builds the reporting week label automatically."
},
"typeVersion": 1
},
{
"id": "ea718811-4cb6-4438-ad83-b232626469d4",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
816,
-64
],
"parameters": {
"color": 7,
"width": 560,
"height": 624,
"content": "## AI report generation\n\nClaude/ChatGPT/.... writes a narrative report 3-4 paragraphs of professional prose, not a task list. Returns HTML and plain text."
},
"typeVersion": 1
},
{
"id": "8def53e1-5a5b-4483-9893-c5f5f3ca2590",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
1424,
-64
],
"parameters": {
"color": 7,
"width": 320,
"height": 624,
"content": "## Send\n\nHTML email delivered to each client's email address. Runs for every active row in the sheet."
},
"typeVersion": 1
},
{
"id": "a5d50954-95af-452c-82ca-c4f5a69fef3c",
"name": "Every Friday at 9 AM",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
144,
176
],
"parameters": {
"rule": {
"interval": [
{
"field": "cronExpression",
"expression": "0 9 * * 5"
}
]
}
},
"typeVersion": 1.3
},
{
"id": "8eb5c5ee-6fbf-4cff-aa4a-890308d680ce",
"name": "Fetch Weekly Data",
"type": "n8n-nodes-base.googleSheets",
"position": [
384,
176
],
"parameters": {
"operation": "getRows",
"documentId": {
"__rl": true,
"mode": "id",
"value": "REPLACE_WITH_YOUR_SHEET_ID"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.5
},
{
"id": "198cb470-11ee-4e69-91ec-e901a6a04f24",
"name": "Normalize Sheet Data",
"type": "n8n-nodes-base.code",
"position": [
624,
176
],
"parameters": {
"jsCode": "// Normalize rows from Google Sheets into the shape the AI prompt needs\n// Expects one row per client with specific column headers (see setup steps)\n\nconst rows = $input.all().map(i => i.json);\nconst results = [];\n\nfor (const row of rows) {\n if (!row['Client Name'] || !row['Client Email']) continue;\n if (row['Status'] === 'paused' || row['Status'] === 'inactive') continue;\n\n // Build metrics text from any column that starts with \"Metric:\"\n const metricLines = [];\n for (const [key, val] of Object.entries(row)) {\n if (key.startsWith('Metric:') && val) {\n const metricName = key.replace('Metric:', '').trim();\n metricLines.push(`${metricName}: ${val}`);\n }\n }\n\n // Get current week label\n const now = new Date();\n const weekStart = new Date(now);\n weekStart.setDate(now.getDate() - now.getDay() + 1); // Monday\n const weekEnd = new Date(weekStart);\n weekEnd.setDate(weekStart.getDate() + 6);\n const fmt = (d) => d.toLocaleDateString('en-GB', { day: 'numeric', month: 'short', year: 'numeric' });\n const weekLabel = `${fmt(weekStart)} \u2013 ${fmt(weekEnd)}`;\n\n results.push({\n json: {\n client_name: row['Client Name'],\n client_email: row['Client Email'],\n project_name: row['Project Name'] || 'Your Project',\n sender_name: row['Sender Name'] || 'Your Team',\n sender_email: row['Sender Email'] || null,\n week_label: weekLabel,\n metrics_text: metricLines.join('\\n') || 'No metrics provided this week',\n tasks_completed: row['Tasks Completed'] || 'No tasks logged',\n tasks_in_progress: row['Tasks In Progress'] || null,\n blockers: row['Blockers'] || null,\n next_week: row['Next Week Plan'] || null\n }\n });\n}\n\nif (results.length === 0) {\n throw new Error('No active client rows found in the sheet. Check that rows have Client Name, Client Email, and Status is not \"paused\" or \"inactive\".');\n}\n\nreturn results;"
},
"typeVersion": 2
},
{
"id": "e5da3f70-a43e-4b30-87fc-d3fcbbccd756",
"name": "Generate Report",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
864,
176
],
"parameters": {
"text": "=Write a weekly client report based on this data.\n\nClient name: {{ $json.client_name }}\nProject name: {{ $json.project_name }}\nReporting period: {{ $json.week_label }}\nSender name (your name): {{ $json.sender_name }}\n\nMetrics this week:\n{{ $json.metrics_text }}\n\nTasks completed:\n{{ $json.tasks_completed }}\n\nTasks in progress:\n{{ $json.tasks_in_progress || 'None noted' }}\n\nBlockers or issues:\n{{ $json.blockers || 'None' }}\n\nNext week plan:\n{{ $json.next_week || 'To be confirmed' }}\n\nWrite a professional narrative report. Do NOT use bullet points. Return ONLY valid JSON.",
"options": {
"systemMessage": "You are a professional account manager writing weekly client progress reports for a freelance agency or consultant. You turn raw numbers and task data into a clear, confident narrative that makes clients feel informed and confident in the team's progress.\n\n## Tone rules\n- Professional but warm \u2014 not corporate, not casual\n- Lead with the most important insight or highlight, not a list of tasks\n- If numbers are down or tasks were incomplete, acknowledge it briefly and pivot to context or next steps \u2014 never hide it, never over-explain it\n- 3-4 short paragraphs max. Each paragraph has one focus.\n- Never use bullet points in the narrative \u2014 this is prose\n- End with a clear forward-looking statement: what happens next week"
},
"promptType": "define",
"hasOutputParser": true
},
"typeVersion": 3
},
{
"id": "be400938-f3d6-451a-acc9-09090b9e55bd",
"name": "Anthropic Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
"position": [
864,
384
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "claude-sonnet-4-5-20250929",
"cachedResultName": "Claude Sonnet 4.5"
},
"options": {
"temperature": 0.5
}
},
"typeVersion": 1.3
},
{
"id": "cd350600-31af-44b4-a00b-227abe9b871a",
"name": "Structured Output Parser",
"type": "@n8n/n8n-nodes-langchain.outputParserStructured",
"position": [
1104,
384
],
"parameters": {
"autoFix": true,
"schemaType": "manual",
"inputSchema": "{\n \"type\": \"object\",\n \"properties\": {\n \"email_subject\": {\n \"type\": \"string\"\n },\n \"report_html\": {\n \"type\": \"string\",\n \"description\": \"Full HTML email body with inline styles, ready to send\"\n },\n \"report_plain\": {\n \"type\": \"string\",\n \"description\": \"Plain text version of the same report\"\n }\n },\n \"required\": [\n \"email_subject\",\n \"report_html\",\n \"report_plain\"\n ],\n \"additionalProperties\": false\n}"
},
"typeVersion": 1.2
},
{
"id": "d2e2ffee-7aff-4994-b93a-65f690425bd0",
"name": "Send Report Email",
"type": "n8n-nodes-base.gmail",
"position": [
1504,
176
],
"parameters": {
"sendTo": "={{ $('Normalize Sheet Data').item.json.client_email }}",
"message": "={{ $input.first().json.output?.report_html || $input.first().json.report_html }}",
"options": {
"appendAttribution": false
},
"subject": "={{ $input.first().json.output?.email_subject || $input.first().json.email_subject }}"
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
},
"typeVersion": 2.1
}
],
"active": false,
"settings": {
"binaryMode": "separate",
"executionOrder": "v1"
},
"versionId": "4ee9a7f9-a49f-46c3-86c6-263003421c77",
"connections": {
"Generate Report": {
"main": [
[
{
"node": "Send Report Email",
"type": "main",
"index": 0
}
]
]
},
"Fetch Weekly Data": {
"main": [
[
{
"node": "Normalize Sheet Data",
"type": "main",
"index": 0
}
]
]
},
"Anthropic Chat Model": {
"ai_languageModel": [
[
{
"node": "Generate Report",
"type": "ai_languageModel",
"index": 0
},
{
"node": "Structured Output Parser",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Every Friday at 9 AM": {
"main": [
[
{
"node": "Fetch Weekly Data",
"type": "main",
"index": 0
}
]
]
},
"Normalize Sheet Data": {
"main": [
[
{
"node": "Generate Report",
"type": "main",
"index": 0
}
]
]
},
"Structured Output Parser": {
"ai_outputParser": [
[
{
"node": "Generate Report",
"type": "ai_outputParser",
"index": 0
}
]
]
}
}
}
Credentials you'll need
Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.
gmailOAuth2googleSheetsOAuth2Api
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow runs every Friday at 9:00 AM, pulls active client status data from Google Sheets, uses Anthropic Claude to generate a narrative weekly report with structured HTML and plain text output, and sends the finished report to each client via Gmail. Runs every Friday at…
Source: https://n8n.io/workflows/16612/ — original creator credit. Request a take-down →
Related workflows
Workflows that share integrations, category, or trigger type with this one. All free to copy and import.
Automatically re-engage old or inactive clients by sending AI-personalized follow-up emails using Claude 3.7 Sonnet, Gmail, and Google Sheets — with smart reply detection to avoid messaging clients wh
If you teach on Udemy at any meaningful scale, you already know the problem: 80% of student messages are variations of the same handful of questions, but every one of them needs a thoughtful reply to
This n8n automation workflow automates the creation, scripting, production, and posting of YouTube videos. It leverages AI (OpenAI), image generation (PIAPI), video rendering (Shotstack), and platform
Created by: Peyton Leveillee Last updated: October 2025
The Multi-Model Agency Content Engine is a high-performance editorial system designed for agencies. It solves the "blank page" problem by alternating between real-world social proof and strategic expe