AutomationFlowsSlack & Telegram › Send Pre-meeting Slack Briefings with Google Calendar and Github

Send Pre-meeting Slack Briefings with Google Calendar and Github

ByPrakash Software @prakashsoftware on n8n.io

This workflow checks Google Calendar hourly for the next upcoming meeting, pulls recent GitHub meeting notes, finds related GitHub PRs and issues, and sends each attendee a Slack DM with a pre-meeting briefing five minutes before the event. Runs every hour on a scheduled trigger…

Cron / scheduled trigger★★★★☆ complexity29 nodesGitHubHTTP RequestSlackGoogle Calendar
Slack & Telegram Trigger: Cron / scheduled Nodes: 29 Complexity: ★★★★☆ Added:

This workflow corresponds to n8n.io template #16351 — we link there as the canonical source.

This workflow follows the GitHub → HTTP Request 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 →

Download .json
{
  "id": "7EQzN4YzDTJiI6dU",
  "name": "Send pre-meeting Slack briefings using Google Calendar, GitHub",
  "tags": [],
  "nodes": [
    {
      "id": "922245e4-7413-4194-b565-ff0be4209829",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        0,
        0
      ],
      "parameters": {
        "width": 480,
        "height": 896,
        "content": "## Send pre-meeting Slack briefings using Google Calendar, GitHub\n\n### How it works\n\n1. The workflow triggers hourly checks from Google Calendar for upcoming events.\n2. It retrieves the last meeting notes if available and checks if there was a previous meeting.\n3. The workflow then extracts relevant keywords from the meeting notes to identify related GitHub pull requests (PRs).\n4. It builds a message for Slack that includes attendees and meeting context.\n5. Finally, it sends direct messages to each attendee on Slack with the meeting context and related PRs.\n\n### Setup steps\n\n- [ ] Configure Google Calendar API credentials in n8n.\n- [ ] Set up GitHub API credentials to access repositories.\n- [ ] Ensure Slack API credentials are ready for sending messages.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "d6c0cb59-a234-42c5-b147-97f0e151c3cc",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        560,
        576
      ],
      "parameters": {
        "color": 7,
        "width": 384,
        "height": 304,
        "content": "## Schedule checks for events\n\nRetrieves events from Google Calendar on an hourly schedule."
      },
      "typeVersion": 1
    },
    {
      "id": "12ad5a8c-54bd-4a87-a604-201ba25701ad",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1264,
        592
      ],
      "parameters": {
        "color": 7,
        "width": 608,
        "height": 272,
        "content": "## Get last meeting details\n\nFetches previous meeting notes and checks if there was a meeting."
      },
      "typeVersion": 1
    },
    {
      "id": "fbed418c-6b6a-4e78-b98f-494cb1bf9973",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3184,
        368
      ],
      "parameters": {
        "color": 7,
        "width": 416,
        "height": 544,
        "content": "## Extract keywords and PRs\n\nExtracts keywords from meeting notes to find relevant GitHub PRs."
      },
      "typeVersion": 1
    },
    {
      "id": "b6fac09c-cd1f-4a69-9d92-328ecacf7f6b",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        4656,
        496
      ],
      "parameters": {
        "color": 7,
        "width": 1472,
        "height": 352,
        "content": "## Handle Slack message construction\n\nBuilds and formats the message for Slack with meeting details and attendees."
      },
      "typeVersion": 1
    },
    {
      "id": "22446a06-0296-4e68-9dda-901d2a6d2a28",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        5456,
        880
      ],
      "parameters": {
        "color": 7,
        "width": 672,
        "height": 352,
        "content": "## Check and send Slack messages\n\nValidates Slack user information and sends out meeting details."
      },
      "typeVersion": 1
    },
    {
      "id": "198c1c51-cb1e-449f-af87-71a31f9a0166",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1904,
        944
      ],
      "parameters": {
        "color": 7,
        "width": 2448,
        "height": 288,
        "content": "## Merge GitHub data\n\nMerges data from GitHub PRs and issues related to the meeting."
      },
      "typeVersion": 1
    },
    {
      "id": "c5d00785-ca27-4911-a6d8-993fdf607aa8",
      "name": "Sticky Note7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        3632,
        0
      ],
      "parameters": {
        "color": 7,
        "width": 2464,
        "height": 464,
        "content": "## Finalize meeting context\n\nPrepares and finalizes the meeting context to be sent to attendees via Slack."
      },
      "typeVersion": 1
    },
    {
      "id": "0344a88c-34d0-4175-9918-181a12bb5d5c",
      "name": "Build Message for Slack",
      "type": "n8n-nodes-base.code",
      "position": [
        4704,
        688
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// --------------------\n// 1. Read inputs safely\n// --------------------\nconst ticketsRaw = $json.tickets ?? [];\n\nconst previousNotes =\n  $('Normalize Calendar and Payloads').first()?.json?.previousMeetingNotes ?? '';\n\nconst meetingTitle =\n  $('Format Calenda Event Payload').first()?.json?.summary ?? 'Meeting';\n\nconst eventStart =\n  $('Format Calenda Event Payload').first()?.json?.eventStart;\n\nconst start = eventStart ? new Date(eventStart) : null;\n\n// --------------------\n// 2. Format meeting time\n// --------------------\nconst meetingTime = start\n  ? start.toLocaleString('en-IN', {\n      weekday: 'short',\n      day: '2-digit',\n      month: 'short',\n      hour: '2-digit',\n      minute: '2-digit'\n    })\n  : '';\n\n// --------------------\n// 3. Clean & validate tickets\n// --------------------\nconst validTickets = ticketsRaw.filter(\n  t => t && t.source && t.id && t.title\n);\n\n// --------------------\n// 4. Build Topics section\n// --------------------\nconst ticketText = validTickets.length\n  ? validTickets\n      .map(t => `\u2022 *[${t.source}]* ${t.id} \u2014 ${t.title}`)\n      .join('\\n')\n  : '_No tickets or PRs found._';\n\n// --------------------\n// 5. Build Previous Notes section\n// --------------------\nconst notesText = previousNotes.trim()\n  ? previousNotes\n      .split('\\n')\n      .map(l => `\u2022 ${l.replace(/^[-\u2022]\\s*/, '')}`)\n      .join('\\n')\n  : '_No previous meeting notes found._';\n\n// --------------------\n// 6. Return Slack Blocks\n// --------------------\nreturn {\n  blocks: [\n    {\n      type: 'header',\n      text: {\n        type: 'plain_text',\n        text: '\ud83e\udde0 Pre-Meeting Context',\n        emoji: true\n      }\n    },\n    {\n      type: 'context',\n      elements: [\n        {\n          type: 'mrkdwn',\n          text: `\ud83d\udcc5 *${meetingTitle}*${meetingTime ? ` \u00b7 *${meetingTime}*` : ''}`\n        }\n      ]\n    },\n    { type: 'divider' },\n    {\n      type: 'section',\n      text: {\n        type: 'mrkdwn',\n        text: `*Topics for Today*\\n${ticketText}`\n      }\n    },\n    { type: 'divider' },\n    {\n      type: 'section',\n      text: {\n        type: 'mrkdwn',\n        text: `*Previous Meeting Summary*\\n${notesText}`\n      }\n    },\n    {\n      type: 'context',\n      elements: [\n        {\n          type: 'mrkdwn',\n          text: '_Please review before the meeting starts._'\n        }\n      ]\n    }\n  ]\n};\n"
      },
      "typeVersion": 2
    },
    {
      "id": "41f84f05-ee8e-4d40-855c-2e9f426240b1",
      "name": "Is Previous Meeting",
      "type": "n8n-nodes-base.filter",
      "position": [
        1520,
        704
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "e6042a4c-041a-4743-b5f9-ee82e6c8f141",
              "operator": {
                "type": "dateTime",
                "operation": "before"
              },
              "leftValue": "={{ $json.created_at }}",
              "rightValue": "={{ $('Format Calenda Event Payload').item.json.eventStart }}"
            }
          ]
        },
        "looseTypeValidation": true
      },
      "typeVersion": 2.3
    },
    {
      "id": "0eb72dff-55d4-497d-9c8d-46b4680c5724",
      "name": "Wait for Time to Come",
      "type": "n8n-nodes-base.wait",
      "position": [
        2416,
        704
      ],
      "parameters": {
        "resume": "specificTime",
        "dateTime": "={{ $json.notifyAt }}"
      },
      "typeVersion": 1.1,
      "alwaysOutputData": true
    },
    {
      "id": "1fee8e24-4a5f-4054-bc66-81ccddbe2cb5",
      "name": "Get PRs from Repo",
      "type": "n8n-nodes-base.github",
      "position": [
        3680,
        112
      ],
      "parameters": {
        "owner": {
          "__rl": true,
          "mode": "name",
          "value": "Your GitHub user name"
        },
        "resource": "repository",
        "repository": {
          "__rl": true,
          "mode": "list",
          "value": "Your repository",
          "cachedResultUrl": "Your repository url",
          "cachedResultName": "Your repository"
        },
        "authentication": "oAuth2",
        "getRepositoryIssuesFilters": {
          "labels": "={{ $json.keywords }}"
        }
      },
      "typeVersion": 1.1,
      "alwaysOutputData": false
    },
    {
      "id": "a3f5e7aa-b886-45e7-abb6-315e622e03aa",
      "name": "Filter PRs Related to Meeting",
      "type": "n8n-nodes-base.code",
      "position": [
        3904,
        112
      ],
      "parameters": {
        "jsCode": "// --------------------\n// 1. Read meeting context (single values)\n// --------------------\nconst keywordsRaw =\n  $('Extract Meeting Keywords').first().json.keywords || '';\n\nconst keywords = keywordsRaw\n  .toLowerCase()\n  .split(' ')\n  .filter(Boolean);\n\nconst lastMeetingDateStr =\n  $('Normalize Calendar and Payloads').first().json.previousMeetingDate || null;\n\nconst lastMeetingDate = lastMeetingDateStr\n  ? new Date(lastMeetingDateStr)\n  : null;\n\n// --------------------\n// 2. Read PR list (multiple items)\n// --------------------\nconst prs = $input.all();\n\n// --------------------\n// 3. Filter PRs\n// --------------------\nconst filteredPRs = prs.filter(item => {\n  const pr = item.json;\n\n  // --- Date filter ---\n  if (lastMeetingDate && pr.created_at) {\n    const prCreatedAt = new Date(pr.created_at);\n    if (prCreatedAt <= lastMeetingDate) {\n      return false;\n    }\n  }\n\n  // --- Keyword relevance ---\n  const text = `${pr.title || ''} ${pr.body || ''}`.toLowerCase();\n\n  const matchesKeyword = keywords.some(k => text.includes(k));\n\n  return matchesKeyword;\n});\n\n// --------------------\n// 4. Return filtered PRs\n// --------------------\nreturn filteredPRs;"
      },
      "typeVersion": 2,
      "alwaysOutputData": true
    },
    {
      "id": "807ec820-0b98-43c6-8390-4b30532b7534",
      "name": "Normalize Attendees and Slack Message",
      "type": "n8n-nodes-base.set",
      "position": [
        4912,
        688
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "8a5490e3-14cf-41ca-b56e-05475e3d92a8",
              "name": "attendees",
              "type": "array",
              "value": "={{ $('Add 5 minute Early Time').first().json.attendees }}"
            },
            {
              "id": "a6bb5f56-eab0-47bd-ae48-f705904b75c1",
              "name": "message",
              "type": "object",
              "value": "={{ $json }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "4cf0d913-a468-462e-932e-fa024ac2fa29",
      "name": "Get User Slack Info from Email",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        5952,
        688
      ],
      "parameters": {
        "url": "https://slack.com/api/users.lookupByEmail",
        "options": {},
        "sendQuery": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "queryParameters": {
          "parameters": [
            {
              "name": "email",
              "value": "={{ $json.email }}"
            }
          ]
        }
      },
      "typeVersion": 4.3
    },
    {
      "id": "e286ddd5-cb69-4530-b2a9-f5c08c003e71",
      "name": "Check Slack User Found",
      "type": "n8n-nodes-base.if",
      "position": [
        5696,
        1072
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "74c0ae69-46aa-4d21-8f8e-b0b8b902a83e",
              "operator": {
                "type": "boolean",
                "operation": "equals"
              },
              "leftValue": "={{ $json.ok }}",
              "rightValue": true
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "6efdf3e2-173f-40a1-b4db-7e31be02b8f0",
      "name": "Send Meeting Context in Slack DM",
      "type": "n8n-nodes-base.slack",
      "position": [
        5984,
        992
      ],
      "parameters": {
        "text": "=Meeting Related Context",
        "user": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.user.id }}"
        },
        "select": "user",
        "blocksUi": "={{ $('Fan Out Attendees').item.json.message }}",
        "messageType": "block",
        "otherOptions": {
          "includeLinkToWorkflow": false
        },
        "authentication": "oAuth2"
      },
      "typeVersion": 2.4
    },
    {
      "id": "fb38b171-69e2-4d85-a843-9ea7884bdd8b",
      "name": "Extract Meeting Keywords",
      "type": "n8n-nodes-base.code",
      "position": [
        2640,
        704
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "const title = ($json.summary || '').trim();\n\nconst keywords = title\n  .toLowerCase()\n  .replace(/[^a-z0-9\\s]/g, '') // remove symbols\n  .split(' ')\n  .filter(w => w.length > 2)   // drop short/noise words\n  .slice(0, 5)\n  .join(' ');\n\nreturn {\n  meetingTitle: title,\n  keywords\n};\n"
      },
      "typeVersion": 2
    },
    {
      "id": "dd1e199b-7371-493a-95e3-16f3d8498cdc",
      "name": "Fan Out Attendees",
      "type": "n8n-nodes-base.code",
      "position": [
        5104,
        688
      ],
      "parameters": {
        "jsCode": "const attendees = $input.first().json.attendees;\n\nconst message =\n  $input.first().json.message;\n\nif (!attendees || attendees.length === 0) {\n  return [];\n}\n\n// Optional: filter declined attendees\nconst valid = attendees.filter(\n  a => a.responseStatus !== 'declined'\n);\n\nreturn valid.map(a => ({\n  json: {\n    email: a.email,\n    message\n  }\n}));\n"
      },
      "typeVersion": 2
    },
    {
      "id": "f2961a78-af8c-4015-b24a-b2668b974f10",
      "name": "Get Last Meeting Notes",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1312,
        704
      ],
      "parameters": {
        "url": "Place GitHub issue url here",
        "options": {},
        "sendQuery": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "queryParameters": {
          "parameters": [
            {
              "name": "labels",
              "value": "meeting-notes"
            },
            {
              "name": "sort",
              "value": "created"
            },
            {
              "name": "direction",
              "value": "desc"
            },
            {
              "name": "per_page",
              "value": "1"
            }
          ]
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "50c94a1b-795f-42fa-8580-75017557437b",
      "name": "HTTP Request",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        3360,
        736
      ],
      "parameters": {
        "url": "https://api.github.com/search/issues",
        "options": {},
        "sendQuery": true,
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "queryParameters": {
          "parameters": [
            {
              "name": "q",
              "value": "={{ $json.keywords }} repo:rajrathodpsspl-coder/n8n-learn is:issue is:open"
            },
            {
              "name": "sort",
              "value": "updated"
            },
            {
              "name": "order",
              "value": "desc"
            }
          ]
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "29c811f2-29eb-47f4-9a68-14d6abb59ff6",
      "name": "Merge Github issues and Github PR",
      "type": "n8n-nodes-base.merge",
      "position": [
        4208,
        1056
      ],
      "parameters": {},
      "typeVersion": 3.2,
      "alwaysOutputData": true
    },
    {
      "id": "3881fd16-f04d-435c-81d6-a1385ac621d7",
      "name": "Normalize Calendar and Payloads",
      "type": "n8n-nodes-base.set",
      "position": [
        1952,
        1072
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "e16008af-f28f-4430-998f-a286632fbf23",
              "name": "previousMeetingNotes",
              "type": "string",
              "value": "={{ $json.body }}"
            },
            {
              "id": "4c6e7c45-69f7-47cf-b66a-6be3aa8bdc0f",
              "name": "eventStart",
              "type": "string",
              "value": "={{ $('Format Calenda Event Payload').item.json.eventStart }}"
            },
            {
              "id": "0e66c8bf-ff51-4a85-a1a1-cf5272f8d77f",
              "name": "summary",
              "type": "string",
              "value": "={{ $('Format Calenda Event Payload').item.json.summary }}"
            },
            {
              "id": "3039ba27-cc43-449b-8100-078554284ac5",
              "name": "attendees",
              "type": "array",
              "value": "={{ $('Format Calenda Event Payload').item.json.attendees }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "dc05e3c7-1843-4f49-a0e5-df8a421acb39",
      "name": "Prepare PRs and issues List",
      "type": "n8n-nodes-base.code",
      "position": [
        4208,
        688
      ],
      "parameters": {
        "jsCode": "const response = $input.first().json;\n\nconst tickets = (response.items || [])\n  .filter(issue =>\n    (issue.labels || []).some(\n      label => label.name?.toLowerCase() === 'meeting-notes'\n    )\n  )\n  .map(issue => ({\n    source: 'GitHub',\n    id: `ISSUE-${issue.number}`,\n    title: issue.title,\n    url: issue.html_url\n  }));\n\nreturn [\n  {\n    json: {\n      tickets\n    }\n  }\n];"
      },
      "typeVersion": 2
    },
    {
      "id": "c37ffd9d-24e7-41e9-9a16-5513a4ca4bbd",
      "name": "Add 5 minute Early Time",
      "type": "n8n-nodes-base.code",
      "position": [
        2176,
        704
      ],
      "parameters": {
        "jsCode": "const start = new Date($input.first().json.eventStart);\nconst notifyAt = new Date(start.getTime() - 5 * 60 * 1000);\n\nreturn {\n  ...$input.first().json,\n  notifyAt\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "005f78a7-96dc-4c70-b3a4-46fc73da5cd8",
      "name": "Format Calenda Event Payload",
      "type": "n8n-nodes-base.code",
      "position": [
        1040,
        704
      ],
      "parameters": {
        "jsCode": "const meetings = $input.all().map(item => item.json);\n\nconst now = new Date();\n\n// Find the next upcoming meeting\nconst nextMeeting = meetings\n  .filter(meeting => new Date(meeting.start.dateTime) > now)\n  .sort((a, b) => new Date(a.start.dateTime) - new Date(b.start.dateTime))[0];\n\nif (!nextMeeting) {\n  return [];\n}\n\nreturn [\n  {\n    json: {\n      eventStart: nextMeeting.start.dateTime,\n      summary: nextMeeting.summary,\n      attendees: nextMeeting.attendees || []\n    }\n  }\n];"
      },
      "typeVersion": 2
    },
    {
      "id": "5c97cdd4-1b94-4c80-a5bf-4a97b10e20f5",
      "name": "If",
      "type": "n8n-nodes-base.if",
      "position": [
        4944,
        304
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "36cb4e3e-7d76-4244-9a56-b0f8c0267e2a",
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $json.tickets.length > 0 }}",
              "rightValue": "false"
            }
          ]
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "7f57f1b3-d69f-4034-abca-2f1f89655d7c",
      "name": "Get events from Google calendar",
      "type": "n8n-nodes-base.googleCalendar",
      "position": [
        800,
        704
      ],
      "parameters": {
        "options": {},
        "calendar": {
          "__rl": true,
          "mode": "list",
          "value": "Select Calenar",
          "cachedResultName": "Calendar name"
        },
        "operation": "getAll"
      },
      "credentials": {
        "googleCalendarOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "465822ce-2689-44d4-a396-dc86c9c39a53",
      "name": "Hourly Check Trigger",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        608,
        704
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "hours"
            }
          ]
        }
      },
      "typeVersion": 1.3
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "executionOrder": "v1"
  },
  "versionId": "584998c4-6614-4d55-94b7-b41a4c087715",
  "connections": {
    "If": {
      "main": [
        [
          {
            "node": "Build Message for Slack",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "HTTP Request": {
      "main": [
        [
          {
            "node": "Merge Github issues and Github PR",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Fan Out Attendees": {
      "main": [
        [
          {
            "node": "Get User Slack Info from Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get PRs from Repo": {
      "main": [
        [
          {
            "node": "Filter PRs Related to Meeting",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Is Previous Meeting": {
      "main": [
        [
          {
            "node": "Normalize Calendar and Payloads",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Hourly Check Trigger": {
      "main": [
        [
          {
            "node": "Get events from Google calendar",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait for Time to Come": {
      "main": [
        [
          {
            "node": "Extract Meeting Keywords",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Slack User Found": {
      "main": [
        [
          {
            "node": "Send Meeting Context in Slack DM",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Last Meeting Notes": {
      "main": [
        [
          {
            "node": "Is Previous Meeting",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Add 5 minute Early Time": {
      "main": [
        [
          {
            "node": "Wait for Time to Come",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Message for Slack": {
      "main": [
        [
          {
            "node": "Normalize Attendees and Slack Message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Meeting Keywords": {
      "main": [
        [
          {
            "node": "Get PRs from Repo",
            "type": "main",
            "index": 0
          },
          {
            "node": "HTTP Request",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare PRs and issues List": {
      "main": [
        [
          {
            "node": "If",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Calenda Event Payload": {
      "main": [
        [
          {
            "node": "Get Last Meeting Notes",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter PRs Related to Meeting": {
      "main": [
        [
          {
            "node": "Merge Github issues and Github PR",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get User Slack Info from Email": {
      "main": [
        [
          {
            "node": "Check Slack User Found",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get events from Google calendar": {
      "main": [
        [
          {
            "node": "Format Calenda Event Payload",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize Calendar and Payloads": {
      "main": [
        [
          {
            "node": "Add 5 minute Early Time",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge Github issues and Github PR": {
      "main": [
        [
          {
            "node": "Prepare PRs and issues List",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize Attendees and Slack Message": {
      "main": [
        [
          {
            "node": "Fan Out Attendees",
            "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.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

This workflow checks Google Calendar hourly for the next upcoming meeting, pulls recent GitHub meeting notes, finds related GitHub PRs and issues, and sends each attendee a Slack DM with a pre-meeting briefing five minutes before the event. Runs every hour on a scheduled trigger…

Source: https://n8n.io/workflows/16351/ — original creator credit. Request a take-down →

More Slack & Telegram workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

Slack & Telegram

Who’s it for

Google Calendar, Slack, HTTP Request
Slack & Telegram

This workflow is ideal for n8n self-hosted users, DevOps engineers, and automation developers who want to automatically back up their n8n workflows to GitHub on a regular basis.

GitHub, n8n, HTTP Request +1
Slack & Telegram

Busy professionals who want a quick daily update combining their calendar, weather, and top news.

Google Calendar, HTTP Request, RSS Feed Read +1
Slack & Telegram

debug. Uses httpRequest, slack, redis, mailgun. Scheduled trigger; 60 nodes.

HTTP Request, Slack, Redis +2
Slack & Telegram

Seller Follow-Up Engine (Enhanced). Uses httpRequest, slack. Scheduled trigger; 44 nodes.

HTTP Request, Slack