Task: Send a monthly summary of days off to payroll by checking Google Calendar events

n8n workflow JSON:
{"id":97,"name":"Collect Absences each month from Google Calendars","nodes":[{"name":"Previous Month","type":"n8n-nodes-base.dateTime","position":[620,480],"parameters":{"value":"={{Date()}}","action":"calculate","options":{},"duration":1,"timeUnit":"months","operation":"subtract"},"typeVersion":1},{"name":"1st of Every month at 8am","type":"n8n-nodes-base.cron","position":[440,480],"parameters":{"triggerTimes":{"item":[{"hour":8,"mode":"everyMonth"}]}},"typeVersion":1},{"name":"Check Summary for Illness or Holiday","type":"n8n-nodes-base.switch","position":[1020,480],"parameters":{"rules":{"rules":[{"value2":"Holiday","operation":"contains"},{"output":1,"value2":"Illness","operation":"contains"}]},"value1":"={{$json[\"summary\"]}}","dataType":"string"},"typeVersion":1},{"name":"Holiday","type":"n8n-nodes-base.noOp","position":[1240,280],"parameters":{},"typeVersion":1},{"name":"Illness","type":"n8n-nodes-base.noOp","position":[1240,460],"parameters":{},"typeVersion":1},{"name":"Filter Holiday Days","type":"n8n-nodes-base.set","position":[1440,280],"parameters":{"values":{"string":[{"name":"Name","value":"={{$json[\"description\"].split(\",\")[0]}}"},{"name":"Days","value":"={{(new Date($json[\"end\"][\"date\"]).getTime() - new Date($json[\"start\"][\"date\"]).getTime()) / (1000 * 3600 * 24)}}"},{"name":"Type","value":"Holiday"}]},"options":{},"keepOnlySet":true},"typeVersion":1},{"name":"Filter Illness Days","type":"n8n-nodes-base.set","position":[1440,460],"parameters":{"values":{"string":[{"name":"Name","value":"={{$json[\"description\"].split(\",\")[0]}}"},{"name":"Days","value":"={{(new Date($json[\"end\"][\"date\"]).getTime() - new Date($json[\"start\"][\"date\"]).getTime()) / (1000 * 3600 * 24)}}"},{"name":"Type","value":"Illness"}]},"options":{},"keepOnlySet":true},"typeVersion":1},{"name":"Merge","type":"n8n-nodes-base.merge","position":[1880,380],"parameters":{},"typeVersion":1},{"name":"Combine Holiday Counts","type":"n8n-nodes-base.function","position":[1640,280],"parameters":{"functionCode":"let names = items.map(e => e.json.Name);\nlet unique_names = [...new Set(names)];\nlet results = [];\n\nfor (thisName of unique_names) {\n  let result = {\n    \"Name\": thisName,\n    \"Days\": 0,\n    \"Type\": \"Holiday\"\n  }\n\n  for (matching_item of items.filter(e => e.json.Name === thisName)) {\n    result.Days += parseInt(matching_item.json.Days);\n  }\n  \n  results.push(result);\n}\n\nreturn results.map(e => { return {json: e} });"},"typeVersion":1},{"name":"Combine Illness Counts","type":"n8n-nodes-base.function","position":[1640,460],"parameters":{"functionCode":"let names = items.map(e => e.json.Name);\nlet unique_names = [...new Set(names)];\nlet results = [];\n\nfor (thisName of unique_names) {\n  let result = {\n    \"Name\": thisName,\n    \"Days\": 0,\n    \"Type\": \"Illness\"\n  }\n\n  for (matching_item of items.filter(e => e.json.Name === thisName)) {\n    result.Days += parseInt(matching_item.json.Days);\n  }\n  \n  results.push(result);\n}\n\nreturn results.map(e => { return {json: e} });"},"typeVersion":1},{"name":"Get previous months events","type":"n8n-nodes-base.googleCalendar","position":[820,480],"parameters":{"options":{"timeMax":"={{new Date().toISOString()}}","timeMin":"={{$json[\"data\"]}}"},"calendar":"your-calendar-id","operation":"getAll","returnAll":true},"credentials":{"googleCalendarOAuth2Api":{"id":"64","name":"Google Calendar account"}},"typeVersion":1},{"name":"Build the message to send","type":"n8n-nodes-base.function","position":[2060,380],"parameters":{"functionCode":"let illnessMessage = \"\";\nlet holidayMessage = \"\";\nlet message = \"Here is a breakdown of absences for the last month.\\n\\n\";\n\n// Loop the input items\nfor (item of items) {\n  if (item.json.Type == \"Holiday\") {\n    holidayMessage += item.json.Name + \" had \" + item.json.Days + \" days\\n\";\n  }\n  if (item.json.Type == \"Illness\") {\n    illnessMessage += item.json.Name + \" had \" + item.json.Days + \" days\\n\";\n  }\n}\n\nif (holidayMessage != \"\") {\n  message += \"Holiday Events\\n\";\n  message += holidayMessage + \"\\n\";\n} else {\n  message += \"No Holiday Events\\n\";\n}\n\nif (illnessMessage != \"\") {\n  message += \"Illness Events\\n\";\n  message += illnessMessage;\n} else {\n  message += \"No Illness Events\\n\";\n}\n\n// Return our message\nreturn [{json: {message}}];"},"typeVersion":1},{"name":"Send email to payroll","type":"n8n-nodes-base.emailSend","position":[2240,380],"parameters":{"text":"={{$json[\"message\"]}}","options":{},"subject":"Absences from last month","toEmail":"payroll-team@mydomain.tld","fromEmail":"n8n@mydomain.tld"},"credentials":{"smtp":{"id":"26","name":"mailtrap"}},"typeVersion":1}],"active":false,"settings":{},"connections":{"Merge":{"main":[[{"node":"Build the message to send","type":"main","index":0}]]},"Holiday":{"main":[[{"node":"Filter Holiday Days","type":"main","index":0}]]},"Illness":{"main":[[{"node":"Filter Illness Days","type":"main","index":0}]]},"Previous Month":{"main":[[{"node":"Get previous months events","type":"main","index":0}]]},"Filter Holiday Days":{"main":[[{"node":"Combine Holiday Counts","type":"main","index":0}]]},"Filter Illness Days":{"main":[[{"node":"Combine Illness Counts","type":"main","index":0}]]},"Combine Holiday Counts":{"main":[[{"node":"Merge","type":"main","index":0}]]},"Combine Illness Counts":{"main":[[{"node":"Merge","type":"main","index":1}]]},"1st of Every month at 8am":{"main":[[{"node":"Previous Month","type":"main","index":0}]]},"Build the message to send":{"main":[[{"node":"Send email to payroll","type":"main","index":0}]]},"Get previous months events":{"main":[[{"node":"Check Summary for Illness or Holiday","type":"main","index":0}]]},"Check Summary for Illness or Holiday":{"main":[[{"node":"Holiday","type":"main","index":0}],[{"node":"Illness","type":"main","index":0}]]}}}