This workflow corresponds to n8n.io template #4420 — we link there as the canonical source.
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 →
{
"meta": {
"templateCredsSetupCompleted": true
},
"nodes": [
{
"id": "c515d0b8-82f7-47f1-9a15-6867c69a8146",
"name": "Microsoft Outlook",
"type": "n8n-nodes-base.microsoftOutlook",
"position": [
480,
0
],
"parameters": {
"filters": {
"custom": "=start/dateTime ge '{{$json.today}}' and start/dateTime lt '{{$json.tomorrow}}'"
},
"resource": "event"
},
"credentials": {
"microsoftOutlookOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 2
},
{
"id": "2c325199-8df6-4c6c-94d2-b54a6d407d27",
"name": "Code",
"type": "n8n-nodes-base.code",
"position": [
260,
0
],
"parameters": {
"jsCode": "const now = new Date();\nconst today = new Date(now.getFullYear(), now.getMonth(), now.getDate());\nconst tomorrow = new Date(today);\ntomorrow.setDate(today.getDate() + 1);\n\nconst isoDate = (d) => d.toISOString().split('.')[0] + 'Z';\n\nreturn [\n {\n json: {\n today: isoDate(today),\n tomorrow: isoDate(tomorrow),\n },\n },\n];\n"
},
"typeVersion": 2
},
{
"id": "0b785775-6430-4fee-8603-e6527957560a",
"name": "Edit Fields",
"type": "n8n-nodes-base.set",
"position": [
700,
0
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "b4e4cf3b-eb02-408e-87e4-85eb52677a52",
"name": "id",
"type": "string",
"value": "={{ $json.id }}"
},
{
"id": "2eb21920-5251-4def-8b24-0db84367bb94",
"name": "subject",
"type": "string",
"value": "={{ $json.subject }}"
},
{
"id": "2840ba2a-1c25-494e-89ad-a18d61629855",
"name": "description",
"type": "string",
"value": "={{ $json.bodyPreview }}"
},
{
"id": "df847006-a390-40cc-a51e-368a213ffb32",
"name": "meeting_start",
"type": "string",
"value": "={{ $json.start.dateTime }}"
},
{
"id": "82e613bc-8de5-4f49-bebe-fbe34f3a1ea8",
"name": "meeting_end",
"type": "string",
"value": "={{ $json.end.dateTime }}"
},
{
"id": "6de1d0ea-48f6-4b95-b810-720dd853b301",
"name": "attendees",
"type": "array",
"value": "={{ $json.attendees }}"
},
{
"id": "3fca7af4-1e83-4e50-b42b-db95e5dba255",
"name": "meeting_organizer",
"type": "string",
"value": "={{ $json.organizer.emailAddress.name }}"
},
{
"id": "5eaa74ef-595d-4a5b-9c37-bdf009cd3b5e",
"name": "meeting_organizer_email",
"type": "string",
"value": "={{ $json.organizer.emailAddress.address }}"
},
{
"id": "d26a7fc5-9782-4237-af89-7afcb42c8bcc",
"name": "meeting_link",
"type": "string",
"value": "={{ $json.webLink }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "9257dcb7-0605-4837-944b-97670cf53317",
"name": "Send Email",
"type": "n8n-nodes-base.emailSend",
"position": [
1140,
0
],
"parameters": {
"html": "={{ $json.html }}",
"options": {
"appendAttribution": false
},
"subject": "={{ $json.subject }}",
"toEmail": "user@example.com",
"fromEmail": "user@example.com"
},
"credentials": {
"smtp": {
"name": "<your credential>"
}
},
"typeVersion": 2.1
},
{
"id": "571a1e32-3d86-4a2f-af35-439557423283",
"name": "Schedule Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
40,
0
],
"parameters": {
"rule": {
"interval": [
{
"triggerAtHour": 8
}
]
}
},
"typeVersion": 1.2
},
{
"id": "649833a8-81e0-4bd2-ad8b-5982ce32fe11",
"name": "Generate HTML",
"type": "n8n-nodes-base.code",
"position": [
920,
0
],
"parameters": {
"jsCode": "const data = $input.all().map(item => item.json);\n\nfunction generateMeetingReminderEmail(meetings) {\n const escapeHtml = (unsafe) =>\n unsafe\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\")\n .replace(/'/g, \"'\");\n\n const meetingCards = meetings.map(meeting => {\n const start = new Date(meeting.meeting_start);\n const end = new Date(meeting.meeting_end);\n\n const options = { year: 'numeric', month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit' };\n const timeString = `${start.toLocaleString('en-US', options)} \u2013 ${end.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit' })}`;\n\n const requiredAttendees = meeting.attendees\n .filter(a => a.type === 'required')\n .map(a => escapeHtml(a.emailAddress.name))\n .join(', ');\n\n const optionalAttendees = meeting.attendees\n .filter(a => a.type === 'optional')\n .map(a => escapeHtml(a.emailAddress.name))\n .join(', ');\n\n return `\n <table width=\"100%\" cellspacing=\"0\" cellpadding=\"0\" style=\"margin-bottom: 20px;\">\n <tr>\n <td align=\"center\" style=\"padding: 0 10px;\">\n <table cellpadding=\"20\" cellspacing=\"0\" width=\"100%\" style=\"max-width: 800px; background-color: #ffffff; border: 1px solid #ddd; border-collapse: collapse;\">\n <tr>\n <td style=\"font-family: Arial, sans-serif; color: #333333; font-size: 14px;\">\n <h2 style=\"margin: 0 0 10px; font-size: 18px; color: #2c3e50;\">${escapeHtml(meeting.subject)}</h2>\n <p><strong>Time:</strong> ${timeString}</p>\n <p><strong>Organizer:</strong> ${escapeHtml(meeting.meeting_organizer)} (${escapeHtml(meeting.meeting_organizer_email)})</p>\n <p><strong>Description:</strong> ${escapeHtml(meeting.description || 'No description provided.')}</p>\n <p><strong>Attendees:</strong><br>${requiredAttendees || 'None'}<br>\n ${optionalAttendees ? `<em>Optional:</em> ${optionalAttendees}` : ''}</p>\n <p>\n <a href=\"${meeting.meeting_link}\" style=\"display: inline-block; padding: 10px 15px; background-color: #0078d4; color: #ffffff; text-decoration: none; border-radius: 4px;\">View in Calendar</a>\n </p>\n </td>\n </tr>\n </table>\n </td>\n </tr>\n </table>\n `;\n }).join('\\n');\n\n return `\n <!DOCTYPE html>\n <html>\n <head>\n <meta charset=\"UTF-8\">\n <title>Today's Meetings</title>\n </head>\n <body style=\"margin: 0; padding: 0; font-family: Arial, sans-serif; background-color: #f4f4f4; color: #333;\">\n <table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\" style=\"padding: 20px;\">\n <tr>\n <td align=\"center\">\n <h1 style=\"font-size: 24px;\">\ud83d\udcc5 Your Meetings Today</h1>\n </td>\n </tr>\n <tr>\n <td>\n ${meetingCards}\n </td>\n </tr>\n </table>\n </body>\n </html>\n `;\n}\n\nconst htmlContent = generateMeetingReminderEmail(data);\n\n// Return HTML + Subject for email node\nreturn [\n {\n json: {\n subject: \"\ud83d\uddd3\ufe0f Your Meetings Today \u2013 \" + (new Date()).toLocaleDateString('en-US', { weekday: 'long', month: 'short', day: 'numeric' }),\n html: htmlContent\n }\n }\n];\n"
},
"typeVersion": 2
},
{
"id": "ca74ba38-8661-45d1-9524-5ed4e978f6a2",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
1060,
160
],
"parameters": {
"width": 280,
"height": 120,
"content": "## Update Email Details\nchange email details to your sender and receiver email addresses."
},
"typeVersion": 1
},
{
"id": "430f51b0-af72-4604-a00e-0d76bb45659c",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-20,
-180
],
"parameters": {
"content": "## Update Time\nconfigure the default time, when this workflow should trigger"
},
"typeVersion": 1
}
],
"connections": {
"Code": {
"main": [
[
{
"node": "Microsoft Outlook",
"type": "main",
"index": 0
}
]
]
},
"Edit Fields": {
"main": [
[
{
"node": "Generate HTML",
"type": "main",
"index": 0
}
]
]
},
"Generate HTML": {
"main": [
[
{
"node": "Send Email",
"type": "main",
"index": 0
}
]
]
},
"Schedule Trigger": {
"main": [
[
{
"node": "Code",
"type": "main",
"index": 0
}
]
]
},
"Microsoft Outlook": {
"main": [
[
{
"node": "Edit Fields",
"type": "main",
"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.
microsoftOutlookOAuth2Apismtp
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow automatically runs at a scheduled time (daily at 8 AM by default), calculates the current day's date range, fetches all calendar events from a specified Microsoft Outlook account for that day, formats these events into a user-friendly HTML email, and then sends…
Source: https://n8n.io/workflows/4420/ — 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.
The FamilyFlow Assistant is your n8n-powered 🚀 companion designed to streamline daily parenting tasks, reduce mental load, and bring a bit more organization and fun into your family life. This versati
This workflow automates the backup of your self-hosted n8n instance by exporting all workflows and saving them as individual files to a designated OneDrive folder. Each file is timestamped for easy ve
Track your product wishlist across Amazon, Walmart, and Google and get an email the moment a price drops. Every morning, reads your products from a Data Table and pulls fresh prices from Amazon, Walma
Synchronize OKRs (Objectives and Key Results) between Monday.com and Jira to automatically calculate progress variance, update dashboards, and share variance reports via Slack and Outlook. This workfl
Generate Weekly n8n Execution Report and Email Summary Automatically runs every 7 days to pull all n8n workflow executions from the past week Merges execution data with workflow information to provide