This workflow corresponds to n8n.io template #9683 — 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": "T20oXbS75AjzqlND",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "Generate EOD Jira Summaries & Weekly Report with Azure OpenAI (GPT-4o-mini) and Gmail",
"tags": [],
"nodes": [
{
"id": "cf39d6c2-8075-48bd-90e2-f5aabe04235e",
"name": "Azure OpenAI Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatAzureOpenAi",
"position": [
672,
640
],
"parameters": {
"model": "gpt-4o-mini",
"options": {}
},
"credentials": {
"azureOpenAiApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "bb0d663a-30fd-40dc-affd-b7bedb5d08bf",
"name": "Azure OpenAI Chat Model1",
"type": "@n8n/n8n-nodes-langchain.lmChatAzureOpenAi",
"position": [
608,
1600
],
"parameters": {
"model": "gpt-4o-mini",
"options": {}
},
"credentials": {
"azureOpenAiApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "654069da-1c35-4475-8a67-1771a9301892",
"name": "Structured Output Parser",
"type": "@n8n/n8n-nodes-langchain.outputParserStructured",
"position": [
736,
1600
],
"parameters": {
"jsonSchemaExample": "{\n \"output\": \"1) **Weekly Overview** \\nThis week (Oct 13\u201317, 2025) saw a **total of 5 items completed**, though a significant **backlog of 32 items remains**, indicating an area for improvement in throughput.\\n\\n2) **Weekly Key Metrics** \\n- **Total items processed (Mon\u2013Fri):** 50 \\n- **Completed (statusCategory: Done or resolution present):** 5 \\n- **In Progress (status.name: In Progress):** 5 \\n- **Backlog/To Do (statusCategory.key: new or status.name: Backlog/To Do):** 32 \\n- **Bugs vs Tasks (issuetype.name counts):** Bugs: 15, Tasks: 15 \\n- **Top assignees (by count, up to 3):** Jyothi Swarup: 50 \\n- **Priority distribution (by priority.name):** Medium: 50 \\n\\n3) **Day-by-Day Highlights** \\n- **Monday:** \\n - Completed 1 task (SCRUM-1: Fix login API timeout) \\n - 5 items in progress (SCRUM-5, SCRUM-2, SCRUM-4, SCRUM-6) \\n- **Tuesday:** \\n - No changes in item status, remained in backlog \\n- **Wednesday:** \\n - No changes, all items unchanged \\n- **Thursday:** \\n - SCRUM-3 and SCRUM-4 remain in the backlog, no new progress \\n- **Friday:** \\n - Status unchanged for remaining items \\n - Continued backlog accumulation \\n\\n4) **Progress & Trends** \\n- Backlog continues to grow with no items moved to completion since Monday. \\n- Completion rate stabilizing at around **1 item/day only.** \\n- Backlog items remain unchanged for most of the week. \\n- All assignee workload appears **highly concentrated**, indicating possible risk. \\n\\n5) **Blockers & Risks (Week)** \\n- **Significant backlog:** Many items (SCRUM-2, SCRUM-3, SCRUM-4, SCRUM-6) remain stagnant. \\n- No visible resolution timelines for in-progress items (particularly SCRUM-5) may lead to increasing risk of missed deadlines. \\n\\n6) **Recommendations (Next Week)** \\n- Prioritize backlog resolution by assigning estimates and deadlines for stalled items. \\n- Focus and urgency required for SCRUM-5 to ensure progress with a clear resolution timeline. \\n- Consider redistributing tasks or adding resources to handle workload effectively. \\n- Schedule daily stand-ups to track progress on backlog items and identify blockers. \\n- Reassess team capacity to meet outstanding sprint deadlines and customer expectations. \\n\\n7) **Completed Work (Week)** \\n- SCRUM-1: Fix login API timeout; resolved on 2025-10-13 \\n\\n8) **Data Snapshot (Appendix)** \\n- { \\\"issuekey\\\": \\\"SCRUM-1\\\", \\\"summary\\\": \\\"Fix login API timeout\\\", \\\"status.name\\\": \\\"Done\\\", \\\"statusCategory.name\\\": \\\"Done\\\", \\\"resolution.name\\\": \\\"Done\\\", \\\"assignee.displayName\\\": \\\"Jyothi Swarup\\\", \\\"priority.name\\\": \\\"Medium\\\", \\\"created\\\": \\\"2025-10-13T13:08:19.220+0530\\\", \\\"updated\\\": \\\"2025-10-13T16:14:36.945+0530\\\" } \\n- { \\\"issuekey\\\": \\\"SCRUM-2\\\", \\\"summary\\\": \\\"Resolve crash on profile photo upload\\\", \\\"status.name\\\": \\\"Backlog\\\", \\\"statusCategory.name\\\": \\\"To Do\\\", \\\"resolution.name\\\": null, \\\"assignee.displayName\\\": \\\"Jyothi Swarup\\\", \\\"priority.name\\\": \\\"Medium\\\", \\\"created\\\": \\\"2025-10-13T13:08:20.563+0530\\\", \\\"updated\\\": \\\"2025-10-13T16:14:41.031+0530\\\" } \\n- { \\\"issuekey\\\": \\\"SCRUM-5\\\", \\\"summary\\\": \\\"Address janky scroll in feed list\\\", \\\"status.name\\\": \\\"In Progress\\\", \\\"statusCategory.name\\\": \\\"In Progress\\\", \\\"resolution.name\\\": null, \\\"assignee.displayName\\\": \\\"Jyothi Swarup\\\", \\\"priority.name\\\": \\\"Medium\\\", \\\"created\\\": \\\"2025-10-13T13:08:29.354+0530\\\", \\\"updated\\\": \\\"2025-10-13T16:14:49.842+0530\\\" } \"\n }"
},
"typeVersion": 1.3
},
{
"id": "88de2233-3d12-4183-a700-4c40f9c91935",
"name": "Structured Output Parser1",
"type": "@n8n/n8n-nodes-langchain.outputParserStructured",
"position": [
800,
640
],
"parameters": {
"jsonSchemaExample": "{\n \"output\": \"1) EOD Summary \\n**Today, one item was successfully completed**, reflecting an overall positive outcome and productive effort by the team. Progress was made on several tasks, while a few remained in the backlog.\\n\\n2) Key Metrics (Today) \\n- Total items processed: 10 \\n- Completed (statusCategory: Done or resolution present): 1 \\n- In Progress (status.name: In Progress): 1 \\n- Backlog/To Do (statusCategory: To Do or status.name: Backlog/To Do): 8 \\n- Bugs vs Tasks (issuetype.name counts): Bugs: 5, Tasks: 5 \\n- Top assignees (by count, up to 3): Jyothi Swarup: 10 \\n- Priority distribution (by priority.name): Medium: 10 \\n\\n3) Notable Updates Today \\n- SCRUM-1: Done; summary: \u201cFix login API timeout\u201d; resolutiondate: 2025-10-13T16:10:59.421+0530 IST \\n- SCRUM-5: In Progress; summary: \u201cAddress janky scroll in feed list\u201d; updated: 2025-10-13T16:14:49.842+0530 IST \\n- SCRUM-2: Backlog; summary: \u201cResolve crash on profile photo upload\u201d; updated: 2025-10-13T16:14:41.031+0530 IST \\n- SCRUM-4: Backlog; summary: \u201cFix dark mode color contrast in buttons\u201d; updated: 2025-10-13T16:14:45.183+0530 IST \\n- SCRUM-6: Backlog; summary: \u201cResolve push notification tap not navigating\u201d; updated: 2025-10-13T16:14:51.576+0530 IST \\n\\n4) Blockers & Risks \\n- SCRUM-2, SCRUM-3, SCRUM-4, and SCRUM-6 are all currently blocked as they remain in the Backlog. \\n- **SCRUM-5** is the only task designated as In Progress, though no resolution timeline is indicated. All other items need to be moved forward to avoid further backlog accumulation.\\n\\n5) Actions for Tomorrow \\n- Assign estimates to Scrum tasks currently in the backlog. \\n- Increase focus on SCRUM-5 to progress towards completion. \\n- Identify and address blockers causing delay in Backlog items. \\n- Re-prioritize items based on urgency and team capacity. \\n- Conduct a quick review of upcoming sprint timelines to align tasks accordingly.\\n\\n6) Data Snapshot (Appendix) \\n- { \\\"issuekey\\\": \\\"SCRUM-1\\\", \\\"summary\\\": \\\"Fix login API timeout\\\", \\\"status.name\\\": \\\"Done\\\", \\\"statusCategory.name\\\": \\\"Done\\\", \\\"resolution.name\\\": \\\"Done\\\", \\\"assignee.displayName\\\": \\\"Jyothi Swarup\\\", \\\"priority.name\\\": \\\"Medium\\\", \\\"created\\\": \\\"2025-10-13T13:08:19.220+0530\\\", \\\"updated\\\": \\\"2025-10-13T16:14:36.945+0530\\\" } \\n- { \\\"issuekey\\\": \\\"SCRUM-2\\\", \\\"summary\\\": \\\"Resolve crash on profile photo upload\\\", \\\"status.name\\\": \\\"Backlog\\\", \\\"statusCategory.name\\\": \\\"To Do\\\", \\\"resolution.name\\\": null, \\\"assignee.displayName\\\": \\\"Jyothi Swarup\\\", \\\"priority.name\\\": \\\"Medium\\\", \\\"created\\\": \\\"2025-10-13T13:08:20.563+0530\\\", \\\"updated\\\": \\\"2025-10-13T16:14:41.031+0530\\\" } \\n- { \\\"issuekey\\\": \\\"SCRUM-5\\\", \\\"summary\\\": \\\"Address janky scroll in feed list\\\", \\\"status.name\\\": \\\"In Progress\\\", \\\"statusCategory.name\\\": \\\"In Progress\\\", \\\"resolution.name\\\": null, \\\"assignee.displayName\\\": \\\"Jyothi Swarup\\\", \\\"priority.name\\\": \\\"Medium\\\", \\\"created\\\": \\\"2025-10-13T13:08:29.354+0530\\\", \\\"updated\\\": \\\"2025-10-13T16:14:49.842+0530\\\" }\"\n }"
},
"typeVersion": 1.3
},
{
"id": "4014c2f1-5ff9-4617-b780-f345669b3a1a",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-336,
496
],
"parameters": {
"content": "## Daily Evening Trigger\u00a0 \nSchedules and initiates the EOD workflow each workday evening automatically."
},
"typeVersion": 1
},
{
"id": "3d75eeb6-2cac-44a0-8b7a-2462f6fdfe61",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
112,
304
],
"parameters": {
"height": 176,
"content": "## Get ALL issues (Jira)\u00a0 \nRetrieves all Jira issues for the day, including statuses, priorities, and assignees, to power the EOD summary."
},
"typeVersion": 1
},
{
"id": "2644c493-fb58-474a-bc2e-89fcf93f8299",
"name": "Get ALL issues",
"type": "n8n-nodes-base.jira",
"position": [
208,
528
],
"parameters": {
"options": {},
"operation": "getAll",
"returnAll": true
},
"credentials": {
"jiraSoftwareCloudApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "f4cee73e-d692-4835-b5a7-c0c94808cb13",
"name": "Flatten Input",
"type": "n8n-nodes-base.code",
"position": [
432,
528
],
"parameters": {
"jsCode": "// n8n Code node: merge all incoming items into a single output array in one item\n\nconst inputItems = $input.all();\nconst combined = [];\n\n// Normalize any value to an array of plain objects\nfunction normalizeToArray(val) {\n if (typeof val === 'string') {\n const trimmed = val.trim();\n try {\n const parsed = JSON.parse(trimmed);\n return Array.isArray(parsed) ? parsed : [parsed];\n } catch {\n return [{ raw: trimmed }];\n }\n }\n if (Array.isArray(val)) return val;\n if (val && typeof val === 'object') return [val];\n return [{ value: val }];\n}\n\n// Merge all items' json into one array\nfor (const item of inputItems) {\n const source = item.json !== undefined ? item.json : item;\n const arr = normalizeToArray(source);\n for (const el of arr) {\n const obj = el && typeof el === 'object' ? el : { value: el };\n combined.push(obj);\n }\n}\n\n// Return a single n8n item containing the whole array\nreturn [\n {\n json: {\n combined, // All input collapsed into one array\n count: combined.length\n }\n }\n];\n"
},
"typeVersion": 2
},
{
"id": "7692b76d-68c2-46f0-8d6c-eff609de74b7",
"name": "Create Summary",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
656,
416
],
"parameters": {
"text": "={{ $json.combined }}",
"options": {
"systemMessage": "You are an End\u2011of\u2011Day (EOD) Report generator for engineering teams. Your job is to read a pasted text blob representing the day\u2019s work (e.g., combined Jira issue array, logs, API responses) and produce a consistent EOD summary every single time using the exact template and rules below. Do not ask questions. Infer context only from the input.\n\nINPUT FORMAT\n- The input may be a single object containing { combined: [...], count: N } or a raw array of issue/work items.\n- Treat JSON keys/values and log lines as source of truth.\n- Today\u2019s local time context: Asia/Kolkata (IST), unless clearly indicated otherwise.\n\nOUTPUT TEMPLATE\n1) EOD Summary\n- One concise paragraph describing today\u2019s overall outcome and the most important takeaway (e.g., completion, progress, blockers).\n\n2) Key Metrics (Today)\n- Total items processed:\n- Completed (statusCategory: Done or resolution present):\n- In Progress (status.name: In Progress):\n- Backlog/To Do (statusCategory: To Do or status.name: Backlog/To Do):\n- Bugs vs Tasks (issuetype.name counts):\n- Top assignees (by count, up to 3):\n- Priority distribution (by priority.name):\n\n3) Notable Updates Today\n- 3\u20136 bullets referencing specific keys and summaries (e.g., SCRUM-1: Done; summary: \u201cFix login API timeout\u201d; resolutiondate/timestamp if present, in IST label).\n\n4) Blockers & Risks\n- Bullets inferred from statuses, null fields (e.g., timeoriginalestimate), overdue sprint windows, inconsistent \u201cactive\u201d vs past endDate, or items showing no progress (created vs updated).\n\n5) Actions for Tomorrow\n- 4\u20137 prioritized, action\u2011oriented steps tied to blockers and carryover (assign, add estimate, re\u2011prioritize, resolve conflicts, test/monitor, etc.).\n\n6) Data Snapshot (Appendix)\n- Quote minimal exact fields for 3\u20135 representative records (issue key, summary, status.name, statusCategory.name, resolution.name, assignee.displayName, priority.name, created, updated). Use original field names exactly.\n\nCLASSIFICATION RULES\n- Completed = statusCategory.key: done OR resolution present.\n- In Progress = status.name: In Progress OR statusCategory.key: indeterminate.\n- Backlog/To Do = status.name: Backlog/To Do OR statusCategory.key: new.\n- Bugs vs Tasks from issuetype.name.\n- Use input\u2019s combined array if present; otherwise use the root array.\n- When timestamps are reported in readable form, label clearly as IST; otherwise preserve originals.\n\nFORMATTING RULES\n- Be concise; no fluff.\n- Headings and section order must never change.\n- Preserve field names exactly (e.g., statuscategorychangedate).\n- Use bold sparingly for 2\u20134 critical items/terms.\n- If a section has no data, write \u201cNone\u201d.\n- Do not add links unless present in the input.\n\nERROR HANDLING\n- If the input appears incomplete or malformed, write \u201cInput appears incomplete or malformed\u201d in EOD Summary, then proceed with whatever can be extracted.\n\nCONSISTENCY CHECK\n- Ensure all six sections are present, labels match exactly, counts are internally consistent, and referenced keys/summaries match the input."
},
"promptType": "define",
"hasOutputParser": true
},
"typeVersion": 2.2
},
{
"id": "514fc953-ea89-46e4-b1c0-c05367d978df",
"name": "Append Summary",
"type": "n8n-nodes-base.googleSheets",
"position": [
1008,
528
],
"parameters": {
"columns": {
"value": {
"Date": "={{ $now.format('dd-MMM-yyyy') }}",
"JSON": "={{ $('Flatten Input').item.json.combined }}",
"Summary": "={{ $json.output }}"
},
"schema": [
{
"id": "Date",
"type": "string",
"display": true,
"required": false,
"displayName": "Date",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "JSON",
"type": "string",
"display": true,
"required": false,
"displayName": "JSON",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Summary",
"type": "string",
"display": true,
"required": false,
"displayName": "Summary",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/14iOjPbhS1kw2sFJy-N-hGads94iz38OjKzlMq8dkgc0/edit#gid=0",
"cachedResultName": "Sheet1"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "14iOjPbhS1kw2sFJy-N-hGads94iz38OjKzlMq8dkgc0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/14iOjPbhS1kw2sFJy-N-hGads94iz38OjKzlMq8dkgc0/edit?usp=drivesdk",
"cachedResultName": "JIRA Daily Reporting"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
},
{
"id": "30e6b160-c87c-40ca-b2cd-75f5ae93d9ff",
"name": "Daily Evening Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-16,
528
],
"parameters": {
"rule": {
"interval": [
{}
]
}
},
"typeVersion": 1.2
},
{
"id": "1e5d7fbe-718a-472f-8d44-efc621042073",
"name": "Friday Evening Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
-80,
1376
],
"parameters": {
"rule": {
"interval": [
{
"field": "weeks",
"triggerAtDay": [
5
],
"triggerAtHour": 20
}
]
}
},
"typeVersion": 1.2
},
{
"id": "f4c8a646-d963-4b84-b442-91ecad3b31d8",
"name": "Get all stored data",
"type": "n8n-nodes-base.googleSheets",
"position": [
144,
1376
],
"parameters": {
"options": {},
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/14iOjPbhS1kw2sFJy-N-hGads94iz38OjKzlMq8dkgc0/edit#gid=0",
"cachedResultName": "Sheet1"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "14iOjPbhS1kw2sFJy-N-hGads94iz38OjKzlMq8dkgc0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/14iOjPbhS1kw2sFJy-N-hGads94iz38OjKzlMq8dkgc0/edit?usp=drivesdk",
"cachedResultName": "JIRA Daily Reporting"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
},
{
"id": "d26c622b-92f7-4826-adeb-ddf57df9daf2",
"name": "Flatten the input",
"type": "n8n-nodes-base.code",
"position": [
368,
1376
],
"parameters": {
"jsCode": "// n8n Code node: merge all incoming items into a single output array in one item\n\nconst inputItems = $input.all();\nconst combined = [];\n\n// Normalize any value to an array of plain objects\nfunction normalizeToArray(val) {\n if (typeof val === 'string') {\n const trimmed = val.trim();\n try {\n const parsed = JSON.parse(trimmed);\n return Array.isArray(parsed) ? parsed : [parsed];\n } catch {\n return [{ raw: trimmed }];\n }\n }\n if (Array.isArray(val)) return val;\n if (val && typeof val === 'object') return [val];\n return [{ value: val }];\n}\n\n// Merge all items' json into one array\nfor (const item of inputItems) {\n const source = item.json !== undefined ? item.json : item;\n const arr = normalizeToArray(source);\n for (const el of arr) {\n const obj = el && typeof el === 'object' ? el : { value: el };\n combined.push(obj);\n }\n}\n\n// Return a single n8n item containing the whole array\nreturn [\n {\n json: {\n combined, // All input collapsed into one array\n count: combined.length\n }\n }\n];\n"
},
"typeVersion": 2
},
{
"id": "a626ce54-881d-4dbc-88ae-19adad2f6389",
"name": "Create Weekly Summary",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
592,
1376
],
"parameters": {
"text": "={{ $json.combined }}",
"options": {
"systemMessage": "You are a Weekly Summary generator for engineering teams. Your job is to read five day-level inputs (Monday through Friday)\u2014each containing data (arrays/objects), JSON details, and an End\u2011of\u2011Day (EOD) summary\u2014and produce a consistent Weekly Summary every single time using the exact template and rules below. Do not ask questions. Infer context only from the input.\n\nINPUT FORMAT\n- The input will include five day entries: Monday, Tuesday, Wednesday, Thursday, Friday.\n- Each day may have:\n - Data: arrays/objects of issues/work items.\n - JSON: raw or stringified JSON representing items.\n - Summary: an EOD summary string following a known template.\n- Treat JSON keys/values and EOD text as source of truth.\n- If multiple structures are present (e.g., combined arrays, raw arrays, stringified JSON), parse/normalize and merge.\n\nOUTPUT TEMPLATE\n1) Weekly Overview\n- One concise paragraph stating the week window (Mon\u2013Fri), overall outcome, and the single most important takeaway (e.g., completion count, major blocker cleared, quality trend).\n\n2) Weekly Key Metrics\n- Total items processed (Mon\u2013Fri):\n- Completed (statusCategory: Done or resolution present):\n- In Progress (status.name: In Progress):\n- Backlog/To Do (statusCategory.key: new or status.name: Backlog/To Do):\n- Bugs vs Tasks (issuetype.name counts):\n- Top assignees (by count, up to 3):\n- Priority distribution (by priority.name):\n\n3) Day-by-Day Highlights\n- Monday: 2\u20134 bullets of notable events (keys, summaries, key timestamps), or \u201cNone\u201d.\n- Tuesday: 2\u20134 bullets, or \u201cNone\u201d.\n- Wednesday: 2\u20134 bullets, or \u201cNone\u201d.\n- Thursday: 2\u20134 bullets, or \u201cNone\u201d.\n- Friday: 2\u20134 bullets, or \u201cNone\u201d.\n\n4) Progress & Trends\n- 3\u20136 bullets comparing days (e.g., rising backlog, stabilization in login, throughput changes, increase/decrease in Done, assignee load shifts).\n\n5) Blockers & Risks (Week)\n- Bullets inferred from the aggregate: persistent backlog items, missing estimates, conflicts (e.g., active sprint with past endDate), stalled items (unchanged status across days), or repeated failures.\n\n6) Recommendations (Next Week)\n- 5\u20138 prioritized, action\u2011oriented steps tied to blockers, throughput, and quality trends. Keep each specific and measurable.\n\n7) Completed Work (Week)\n- 3\u20138 bullets referencing key completions with issue keys, summaries, resolution/resolutiondate/timestamps (label IST if converting).\n\n8) Data Snapshot (Appendix)\n- Quote minimal exact fields for 5\u201310 representative records across the week:\n - issue key, summary, status.name, statusCategory.name/key, resolution.name, assignee.displayName, priority.name, created, updated.\n - Preserve original field names exactly as found.\n\nCLASSIFICATION & AGGREGATION RULES\n- Completed = statusCategory.key: done OR resolution present.\n- In Progress = status.name: In Progress OR statusCategory.key: indeterminate.\n- Backlog/To Do = status.name: Backlog/To Do OR statusCategory.key: new.\n- Bugs vs Tasks from issuetype.name.\n- Normalize sources in this order per day: combined array \u2192 root array/object \u2192 stringified JSON \u2192 EOD Summary counts (as fallback only).\n- When computing weekly metrics, sum unique items across all days (deduplicate by key if present).\n- Age/staleness: use created vs updated; note items unchanged across multiple days.\n- Timezone: Prefer Asia/Kolkata (IST) when converting; if preserving originals, label as-is.\n\nFORMATTING RULES\n- Be concise; no fluff.\n- Headings and section order must never change.\n- Preserve field names exactly (e.g., statuscategorychangedate).\n- Use bold sparingly for 3\u20136 critical items/terms.\n- If a section has no data, write \u201cNone\u201d.\n- Do not add links unless present in the input.\n\nERROR HANDLING\n- If one or more days are missing or malformed, state \u201cSome daily inputs appear incomplete or malformed\u201d in Weekly Overview, then proceed with whatever can be extracted.\n- If a metric cannot be computed due to missing fields, set it to \u201cUnknown\u201d and briefly explain under Blockers & Risks.\n\nCONSISTENCY CHECK\n- Ensure all eight sections are present, labels match exactly, counts are internally consistent, and referenced keys/summaries match the input."
},
"promptType": "define",
"hasOutputParser": true
},
"typeVersion": 2.2
},
{
"id": "82ae1eaa-b298-4a81-a839-248558ce2fd9",
"name": "Create Email",
"type": "n8n-nodes-base.code",
"position": [
944,
1376
],
"parameters": {
"jsCode": "// filename: n8n-generate-weekly-summary-email.js\n\n/**\n * n8n Code node (JavaScript) \u2013 Fixes \u201cCode doesn't return items properly\u201d\n * and returns a valid array of items with the generated HTML email.\n *\n * Input expectation:\n * - Each incoming item has a field `output` (string) containing the weekly summary text\n * with sections 1) .. 8) as provided by your AI Agent node.\n *\n * Output:\n * - Returns an array with ONE item:\n * { json: { html: \"<!-- full HTML email -->\", subject: \"Weekly Summary\", plainTextPreview: \"...\" } }\n *\n * If multiple input items exist, it uses the first one with `output` present.\n *\n * Place this code in your \u201cCode\u201d node and ensure the previous node passes an item\n * with `output` in `item.json.output`.\n */\n\n// --------------- Helper functions ---------------\n\n// Basic HTML escaping\nfunction escapeHtml(str) {\n return String(str)\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"');\n}\n\n// Convert \"1) **Weekly Overview**\" -> \"Weekly Overview\"\nfunction cleanHeading(headingText) {\n let h = headingText.replace(/^\\d\\)\\s*/, '');\n h = h.replace(/\\*\\*/g, '').trim();\n return h;\n}\n\n// Inline formatting: bold **text**, issue keys as pills\nfunction inlineFormat(text) {\n let t = escapeHtml(text);\n t = t.replace(/\\*\\*(.+?)\\*\\*/g, '<strong>$1</strong>');\n t = t.replace(/\\b([A-Z]+-\\d+)\\b/g, '<span class=\"pill\">$1</span>');\n return t;\n}\n\n// Render section content: bullets, paragraphs, snapshot code blocks\nfunction renderSectionContent(content) {\n if (!content) return '<p class=\"muted\">None</p>';\n\n const lines = content.split('\\n');\n const blocks = [];\n let currentList = null;\n\n const flushList = () => {\n if (currentList && currentList.items.length) {\n const li = currentList.items.map(i => `<li>${inlineFormat(i)}</li>`).join('');\n blocks.push(`<ul class=\"metric-list\">${li}</ul>`);\n }\n currentList = null;\n };\n\n for (let rawLine of lines) {\n const line = rawLine.trim();\n\n if (line.length === 0) {\n flushList();\n continue;\n }\n if (/^-\\s+/.test(line)) {\n if (!currentList) currentList = { items: [] };\n currentList.items.push(line.replace(/^-\\s+/, '').trim());\n continue;\n }\n flushList();\n\n // JSON-like snapshot lines -> code block\n if (/^\\{.+\\}$/.test(line) || line.startsWith('{ \"') || line.startsWith('- {')) {\n const cleaned = line.replace(/^-+\\s*/, '');\n blocks.push(`<div class=\"code\">${escapeHtml(cleaned)}</div>`);\n } else {\n blocks.push(`<p>${inlineFormat(line)}</p>`);\n }\n }\n\n flushList();\n return blocks.join('\\n');\n}\n\n// Build email HTML from the `output` string\nfunction buildEmailHtml(outputText) {\n // Find section headings like \"1) **Weekly Overview**\"\n const headingRegex = /\\n?\\s*(\\d\\)\\s\\*\\*?[^\\n]+?\\*\\*?\\s*)/g;\n const parts = [];\n let match;\n\n while ((match = headingRegex.exec(outputText)) !== null) {\n const headingText = match[1];\n const startIndexForContent = headingRegex.lastIndex;\n const cleanedHeading = cleanHeading(headingText);\n\n // Set previous section content boundary\n if (parts.length > 0) {\n parts[parts.length - 1].content = outputText.slice(parts[parts.length - 1].startIndex, match.index).trim();\n }\n\n parts.push({\n heading: cleanedHeading,\n startIndex: startIndexForContent,\n content: '',\n });\n }\n\n if (parts.length > 0) {\n const last = parts[parts.length - 1];\n last.content = outputText.slice(last.startIndex).trim();\n } else {\n // Fallback: whole text as one section\n parts.push({\n heading: 'Weekly Summary',\n content: outputText.trim(),\n });\n }\n\n const sectionHtml = parts.map(({ heading, content }) => {\n return `\n <section class=\"card\">\n <h2 class=\"section-title\">${escapeHtml(heading)}</h2>\n ${renderSectionContent(content)}\n </section>\n `;\n }).join('\\n');\n\n const generatedAtIst = escapeHtml(new Date().toLocaleString('en-IN', { timeZone: 'Asia/Kolkata' }));\n\n const html = `\n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"UTF-8\" />\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n<title>Weekly Summary</title>\n<style>\n :root {\n --bg: #f7f8fa;\n --card-bg: #ffffff;\n --text: #111827;\n --muted: #6b7280;\n --primary: #2563eb;\n --border: #e5e7eb;\n }\n body {\n margin: 0;\n background: var(--bg);\n color: var(--text);\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Inter, Oxygen, Ubuntu, Cantarell, \"Fira Sans\", \"Droid Sans\", \"Helvetica Neue\", Arial, sans-serif;\n line-height: 1.6;\n }\n .container {\n max-width: 760px;\n margin: 0 auto;\n padding: 24px 16px;\n }\n .header {\n background: linear-gradient(135deg, #eef2ff, #f0fdf4);\n border: 1px solid var(--border);\n border-radius: 14px;\n padding: 20px;\n margin-bottom: 16px;\n }\n .title {\n margin: 0;\n font-size: 22px;\n font-weight: 700;\n }\n .subtitle {\n margin: 6px 0 0;\n font-size: 14px;\n color: var(--muted);\n }\n .card {\n background: var(--card-bg);\n border: 1px solid var(--border);\n border-radius: 12px;\n padding: 18px;\n margin: 12px 0;\n box-shadow: 0 2px 6px rgba(31, 41, 55, 0.06);\n }\n .section-title {\n margin: 0 0 12px;\n font-size: 18px;\n font-weight: 700;\n color: var(--text);\n border-left: 3px solid var(--primary);\n padding-left: 10px;\n }\n p { margin: 10px 0; }\n ul.metric-list { padding-left: 18px; margin: 8px 0; }\n ul.metric-list li { margin: 6px 0; }\n .pill {\n display: inline-block;\n font-size: 12px;\n padding: 4px 8px;\n border-radius: 999px;\n background: #eef2ff;\n color: #1e3a8a;\n border: 1px solid #e5e7eb;\n margin-right: 6px;\n }\n .code {\n font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace;\n font-size: 12px;\n background: #f3f4f6;\n border: 1px solid var(--border);\n border-radius: 8px;\n padding: 8px;\n white-space: pre-wrap;\n word-break: break-word;\n margin: 8px 0;\n }\n .footer {\n text-align: center;\n color: var(--muted);\n font-size: 12px;\n margin-top: 18px;\n }\n @media (max-width: 480px) {\n .container { padding: 18px 12px; }\n .title { font-size: 20px; }\n .section-title { font-size: 17px; }\n }\n</style>\n</head>\n<body>\n <div class=\"container\">\n <header class=\"header\">\n <h1 class=\"title\">Weekly Summary</h1>\n <p class=\"subtitle\">Generated automatically from your weekly report data.</p>\n </header>\n\n ${sectionHtml}\n\n <footer class=\"footer\">\n Sent via automated workflow \u00b7 ${generatedAtIst} IST\n </footer>\n </div>\n</body>\n</html>\n `.trim();\n\n return html;\n}\n\n// Create a short plain text preview (for email providers that show a preview line)\nfunction buildPlainPreview(outputText) {\n // Take the first line after Weekly Overview for a preview\n const firstLine = outputText.split('\\n').find(l => l.trim().length > 0) || 'Weekly Summary';\n return firstLine.replace(/\\*\\*/g, '').replace(/\\s+/g, ' ').trim().slice(0, 160);\n}\n\n// --------------- Main n8n code ---------------\n\nconst items = $input.all();\n\n// Pick the first item that has `output`\nlet outputText = null;\nfor (const it of items) {\n if (it && it.json && typeof it.json.output === 'string' && it.json.output.trim().length > 0) {\n outputText = it.json.output;\n break;\n }\n}\n\n// If not found, try the first item's whole JSON converted to string\nif (!outputText) {\n if (items.length > 0 && items[0].json) {\n outputText = JSON.stringify(items[0].json);\n } else {\n outputText = 'Weekly Summary\\n\\nNo output text found in incoming items.';\n }\n}\n\n// Build HTML and preview\nconst html = buildEmailHtml(outputText);\nconst preview = buildPlainPreview(outputText);\n\n// Return one n8n item with the email payload\nreturn [\n {\n json: {\n subject: 'Weekly Summary',\n html,\n plainTextPreview: preview,\n },\n },\n];\n"
},
"typeVersion": 2
},
{
"id": "9d53e156-2c55-412f-a342-ac7b15be99f9",
"name": "Email to Stakeholders",
"type": "n8n-nodes-base.gmail",
"position": [
1168,
1376
],
"parameters": {
"sendTo": "user@example.com",
"message": "={{ $json.html }}",
"options": {},
"subject": "={{ $json.subject }}"
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
},
"typeVersion": 2.1
},
{
"id": "551aec75-3b84-4fe9-a859-c224e194463f",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
352,
688
],
"parameters": {
"height": 176,
"content": "## Flatten Input\u00a0 \nNormalizes and flattens the Jira JSON into a lighter structure so downstream nodes can parse consistently."
},
"typeVersion": 1
},
{
"id": "74294bfe-8fcb-4b01-b3de-015ba940405e",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
640,
176
],
"parameters": {
"height": 192,
"content": "## Chat Model (EOD)\u00a0 \nGenerates a structured End\u2011of\u2011Day summary from the flattened issue data using the configured Azure OpenAI model."
},
"typeVersion": 1
},
{
"id": "c02f0d08-1761-4f59-bdde-1c430082776f",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
944,
704
],
"parameters": {
"height": 192,
"content": "## Append Summary (Sheet)\u00a0 \nWrites the EOD summary and the day\u2019s metadata into the Excel/Sheet store for later weekly aggregation."
},
"typeVersion": 1
},
{
"id": "8539c40a-70dc-4e66-a2a4-02fe9deca977",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
-400,
1360
],
"parameters": {
"height": 176,
"content": "## Friday Evening Trigger\u00a0 \nStarts the weekly compilation workflow every Friday evening to build and send the weekly report."
},
"typeVersion": 1
},
{
"id": "affe1837-b2b5-4337-80a0-59adca265027",
"name": "Sticky Note6",
"type": "n8n-nodes-base.stickyNote",
"position": [
64,
1168
],
"parameters": {
"height": 176,
"content": "## Get all stored data (Sheet)\u00a0 \nReads the week\u2019s EOD entries from the sheet, providing the full set of daily summaries for the weekly report."
},
"typeVersion": 1
},
{
"id": "2e86ba0f-1810-478b-b68b-f5e949b442e8",
"name": "Sticky Note7",
"type": "n8n-nodes-base.stickyNote",
"position": [
304,
1536
],
"parameters": {
"height": 176,
"content": "## Flatten the input (Weekly)\u00a0 \nConverts the read rows into a unified format for the weekly AI summarization step."
},
"typeVersion": 1
},
{
"id": "5b3bc309-60b3-467c-bc62-3a04b7b52e32",
"name": "Sticky Note8",
"type": "n8n-nodes-base.stickyNote",
"position": [
576,
1168
],
"parameters": {
"height": 176,
"content": "## Chat Model (Weekly)\u00a0 \nProduces a consistent Weekly Summary by analyzing the five daily EOD entries (Monday\u2013Friday)."
},
"typeVersion": 1
},
{
"id": "6ab5b8a2-7aa4-4795-aa2b-2514b5045776",
"name": "Sticky Note9",
"type": "n8n-nodes-base.stickyNote",
"position": [
880,
1536
],
"parameters": {
"height": 176,
"content": "## Create Email\u00a0 \nTransforms the weekly summary into styled, mobile\u2011friendly HTML with a clear subject and preview."
},
"typeVersion": 1
},
{
"id": "91a7270d-1ad6-4d10-9182-29068b710763",
"name": "Sticky Note10",
"type": "n8n-nodes-base.stickyNote",
"position": [
1104,
1168
],
"parameters": {
"height": 176,
"content": "## Email to Stakeholders\u00a0 \nSends the final weekly report email to the stakeholder list using the configured email provider."
},
"typeVersion": 1
}
],
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "8897253f-0b1a-4ea3-bf93-9b00f633c6e3",
"connections": {
"Create Email": {
"main": [
[
{
"node": "Email to Stakeholders",
"type": "main",
"index": 0
}
]
]
},
"Flatten Input": {
"main": [
[
{
"node": "Create Summary",
"type": "main",
"index": 0
}
]
]
},
"Create Summary": {
"main": [
[
{
"node": "Append Summary",
"type": "main",
"index": 0
}
]
]
},
"Get ALL issues": {
"main": [
[
{
"node": "Flatten Input",
"type": "main",
"index": 0
}
]
]
},
"Flatten the input": {
"main": [
[
{
"node": "Create Weekly Summary",
"type": "main",
"index": 0
}
]
]
},
"Get all stored data": {
"main": [
[
{
"node": "Flatten the input",
"type": "main",
"index": 0
}
]
]
},
"Create Weekly Summary": {
"main": [
[
{
"node": "Create Email",
"type": "main",
"index": 0
}
]
]
},
"Daily Evening Trigger": {
"main": [
[
{
"node": "Get ALL issues",
"type": "main",
"index": 0
}
]
]
},
"Friday Evening Trigger": {
"main": [
[
{
"node": "Get all stored data",
"type": "main",
"index": 0
}
]
]
},
"Azure OpenAI Chat Model": {
"ai_languageModel": [
[
{
"node": "Create Summary",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Azure OpenAI Chat Model1": {
"ai_languageModel": [
[
{
"node": "Create Weekly Summary",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Structured Output Parser": {
"ai_outputParser": [
[
{
"node": "Create Weekly Summary",
"type": "ai_outputParser",
"index": 0
}
]
]
},
"Structured Output Parser1": {
"ai_outputParser": [
[
{
"node": "Create Summary",
"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.
azureOpenAiApigmailOAuth2googleSheetsOAuth2ApijiraSoftwareCloudApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Automates daily EOD summaries from Jira issues into an Excel sheet, then compiles a weekly summary using Azure OpenAI (GPT-4o-mini) and delivers it to stakeholders via email. Gain consistent reporting, clear insights, and hands-free delivery. ✨📧 Fetches Jira issues and extracts…
Source: https://n8n.io/workflows/9683/ — 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.
Automate Jira backlog management with intelligent cleanup, prioritization, and AI-powered reporting. This workflow scans daily to identify stale issues, missing priorities, and overdue tasks — auto-up
Automate post-purchase workflows by instantly fetching successful Stripe payments, matching them to corresponding automation templates in Google Sheets, and sending customers personalized access email
Automate customer feedback analysis and action planning by integrating Monday.com, Azure OpenAI, Jira, Google Sheets, and Outlook. This workflow classifies customer feedback with AI, calculates busine
This workflow automates end-to-end pre-surgery checklist reminders and confirmation tracking for healthcare operations teams. It ensures patients receive timely preparation instructions, can confirm c
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