This workflow corresponds to n8n.io template #11148 — we link there as the canonical source.
This workflow follows the Chainllm → 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": "S2rFuJlSshS6Wbv7",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "AI Pre-Meeting Assistant (Automated Hourly Report)",
"tags": [
{
"id": "X5EwACMVJgXp8ItT",
"name": "Google Calendar",
"createdAt": "2025-11-23T06:03:41.906Z",
"updatedAt": "2025-11-23T06:03:41.906Z"
},
{
"id": "XFT3OzkRHDCJIJiE",
"name": "LLM",
"createdAt": "2025-11-23T06:03:49.901Z",
"updatedAt": "2025-11-23T06:03:49.901Z"
},
{
"id": "eHPxfsiXCpmwBeKm",
"name": "Pre-Meeting Assistant",
"createdAt": "2025-11-23T06:04:57.533Z",
"updatedAt": "2025-11-23T06:04:57.533Z"
}
],
"nodes": [
{
"id": "5dd6af73-03b8-4af9-b51a-488feb20226d",
"name": "Get Message Contents",
"type": "n8n-nodes-base.gmail",
"position": [
2576,
448
],
"parameters": {
"simple": false,
"options": {},
"messageId": "={{ $json.id }}",
"operation": "get"
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
},
"typeVersion": 2.1
},
{
"id": "5e220d55-752f-47af-8288-f7f31fa5df97",
"name": "Simplify Emails",
"type": "n8n-nodes-base.set",
"position": [
2800,
448
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "2006c806-42db-4457-84c2-35f59ed39018",
"name": "date",
"type": "string",
"value": "={{ $json.date }}"
},
{
"id": "872278d2-b97c-45ba-a9d3-162f154fe7dc",
"name": "subject",
"type": "string",
"value": "={{ $json.subject }}"
},
{
"id": "282f03e9-1d0f-4a17-b9ed-75b44171d4ee",
"name": "text",
"type": "string",
"value": "={{ $json.text }}"
},
{
"id": "9421776c-ff53-4490-b0e1-1e610534ba25",
"name": "from",
"type": "string",
"value": "={{ $json.from.value[0].name }} ({{ $json.from.value[0].address }})"
},
{
"id": "3b6716e8-5582-4da3-ae9d-e8dd1afad530",
"name": "to",
"type": "string",
"value": "={{ $json.to.value[0].name }} ({{ $json.to.value[0].address }})"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "8cfe9075-4c20-4153-96de-5d1869c32936",
"name": "Check For Upcoming Meetings",
"type": "n8n-nodes-base.googleCalendar",
"position": [
880,
480
],
"parameters": {
"limit": 5,
"options": {
"orderBy": "startTime",
"timeMax": "={{ $now.toUTC().plus(2, 'hour').startOf('hour') }}",
"timeMin": "={{ $now.toUTC().plus(1, 'hour').startOf('hour') }}",
"singleEvents": true
},
"calendar": {
"__rl": true,
"mode": "list",
"value": "user@example.com",
"cachedResultName": "user@example.com"
},
"operation": "getAll"
},
"credentials": {
"googleCalendarOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 1.2
},
{
"id": "2ad3902c-1f9f-438c-b49f-d6126e87a0b5",
"name": "Extract Attendee Information",
"type": "@n8n/n8n-nodes-langchain.informationExtractor",
"position": [
1248,
480
],
"parameters": {
"text": "=start: {{ $json.start.dateTime }}\nmeeting url: {{ $json.hangoutLink }}\nsummary: {{ $json.summary }}\ndescription: {{ $json.description }}\norganizer: ({{ $json.organizer.email }})\nattendees: {{ $json.attendees.filter(item => !item.organizer).map(item => item.email).join(',') }}",
"options": {
"systemPromptTemplate": "You are an expert extraction algorithm. Try to link any information found in the description to help fill in the attendee details.\nIf you do not know the value of an attribute asked to extract, you may omit the attribute's value."
},
"schemaType": "manual",
"inputSchema": "{\n\t\"type\": \"object\",\n\t\"properties\": {\n\t\t\"attendees\": {\n \"type\": \"array\",\n \"description\": \"list of attendees excluding the meeting organiser\",\n \"items\": {\n \"type\": \"object\",\n \"properties\": {\n \"name\": { \"type\": \"string\" },\n \"email\": { \"type\": \"string\" },\n \"linkedin_url\": { \"type\": \"string\" }\n }\n }\n\t\t}\n\t}\n}"
},
"typeVersion": 1
},
{
"id": "03f95dba-11e4-4603-ae04-50ed06c614a2",
"name": "Get Last Correspondence",
"type": "n8n-nodes-base.gmail",
"position": [
2064,
464
],
"parameters": {
"limit": 1,
"filters": {
"sender": "={{ $json.name }}"
},
"operation": "getAll"
},
"credentials": {
"gmailOAuth2": {
"name": "<your credential>"
}
},
"typeVersion": 2.1,
"alwaysOutputData": true
},
{
"id": "62e4c7ba-e427-444b-8447-df5e6b7b84a1",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
512,
272
],
"parameters": {
"color": 7,
"width": 585,
"height": 545,
"content": "## 1. Periodically Search For Upcoming Meetings\n\nHere, we'll set it for 1 hour intervals to check for meetings scheduled in our Google Calendar. You may need to play with the intervals and frequency depending on how many meetings you typically have.\nWe're going to get all meetings scheduled for the hour starting right at the next hour."
},
"typeVersion": 1
},
{
"id": "41387f48-b00e-4b4e-a4e5-afc9012d1b19",
"name": "Schedule Trigger",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
624,
480
],
"parameters": {
"rule": {
"interval": [
{
"field": "hours"
}
]
}
},
"typeVersion": 1.2
},
{
"id": "6fa36d5b-b60e-4385-a0c1-a184a662c5f6",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
1152,
272
],
"parameters": {
"color": 7,
"width": 608,
"height": 542,
"content": "## 2. Extract Attendee Details From Invite\n[Learn more about the Information Extractor node](https://docs.n8n.io/integrations/builtin/cluster-nodes/root-nodes/n8n-nodes-langchain.information-extractor/)\n\nWe'll extract this information for each attendee using the Information Extractor node. This convenient node uses AI to parse and extract which saves us from writing complex pattern matching code otherwise."
},
"typeVersion": 1
},
{
"id": "1d226e44-bfe8-470d-ab53-ad10c045ec6a",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
3600,
272
],
"parameters": {
"color": 7,
"width": 546,
"height": 550,
"content": "## 5. Pre-Meeting Summary Notification\n\nUse the LLM node to summarize the discussion content and generate the pre-meeting notification."
},
"typeVersion": 1
},
{
"id": "4b3e30da-7c6b-4f96-9957-6e813a01f747",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
4192,
272
],
"parameters": {
"color": 7,
"width": 435,
"height": 550,
"content": "## 6. Send Notification via Slack\n\nNot using Slack ? Simply swap this our for Twilio, Telegram, WhatsApp and others."
},
"typeVersion": 1
},
{
"id": "9b3ebb86-04bf-4eb0-895b-c7820f9d4bad",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
1792,
272
],
"parameters": {
"color": 7,
"width": 1127,
"height": 543,
"content": "## 3. Fetch Last Email Correspondance\n\nFetching our attendee's last email will definitely help the user \"pick up\" from when they last last off. To do this, we'll assume a Gmail user and use the Gmail node to filter messages by the attendee's email address."
},
"typeVersion": 1
},
{
"id": "c6b5b73c-8cd6-4389-9a92-b60b3613898f",
"name": "Return Email Success",
"type": "n8n-nodes-base.set",
"position": [
3408,
448
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "fc4b63a7-ad4d-49ff-9d42-715760910f6a",
"name": "email_summary",
"type": "string",
"value": "={{ $json.text }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "63e85aa1-34a7-4600-bb3e-f737901d500c",
"name": "Has Emails?",
"type": "n8n-nodes-base.if",
"position": [
2304,
464
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "ff11640a-33e4-4695-a62c-7dcab57f0ae5",
"operator": {
"type": "object",
"operation": "notEmpty",
"singleValue": true
},
"leftValue": "={{ $json }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2.2
},
{
"id": "652c2a95-09f8-4373-b3db-d6f1743bbd07",
"name": "Attendees to List",
"type": "n8n-nodes-base.splitOut",
"position": [
1584,
480
],
"parameters": {
"options": {},
"fieldToSplitOut": "output.attendees"
},
"typeVersion": 1
},
{
"id": "0b1d4ab5-0dcb-4b8b-ab30-ccfa0fd5f2b7",
"name": "Has Email Address?",
"type": "n8n-nodes-base.if",
"position": [
1840,
480
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "and",
"conditions": [
{
"id": "1382e335-bfae-4665-a2ee-a05496a7b463",
"operator": {
"type": "string",
"operation": "exists",
"singleValue": true
},
"leftValue": "={{ $json.email }}",
"rightValue": ""
}
]
}
},
"typeVersion": 2.2
},
{
"id": "820f3776-5bb2-419d-86ea-d0a95f2f2043",
"name": "Sticky Note12",
"type": "n8n-nodes-base.stickyNote",
"position": [
2960,
272
],
"parameters": {
"color": 7,
"width": 594,
"height": 549,
"content": "## 4. Summarize Correspondance For Attendee\n\nNext, we'll generate a shorter version of the email(s) using the Basic LLM node - useful if the email was part of a large chain. The goal here is, if applicable, to remind the user of the conversion with this attendee and highlight any expectations which might be set before going into the meeting."
},
"typeVersion": 1
},
{
"id": "0056a020-7524-4ac0-bcb0-76eed8dfbfbd",
"name": "Sticky Note13",
"type": "n8n-nodes-base.stickyNote",
"position": [
-176,
160
],
"parameters": {
"width": 613,
"height": 860,
"content": "## Overiew\n\nThis workflow builds an AI meeting assistant who sends information-dense pre-meeting notifications for a user's upcoming meetings. \n\n### How It Works\n\n* A scheduled trigger fires hourly and checks for upcoming meetings within the hour.\n* When found, a search for last correspondence + recent activity is performed for each attendee.\n* Using available correspondance, an AI/LLM is used to summarize this information and generate a short notification message which should help the user prepare for the meeting.\n* The notification is finally sent to the user's Slack.\n\n### Set up Step\n\n#### Google Cloud\nCreate the [credentials](https://console.cloud.google.com/apis/credentials) and replace them in the workflow.\nPlease [enable](https://console.cloud.google.com/apis/dashboard) the following APIs:\n- Gmail API\n- Google Calendar API\n\n#### OpenAI\n\n- Create the [credentials](https://docs.n8n.io/integrations/builtin/credentials/openai/) as instructed\n- Replace your credentials and connect.\n\n#### Slack\n\n- Create the [credentials](https://docs.n8n.io/integrations/builtin/credentials/slack/?utm_source=n8n_app&utm_medium=credential_settings&utm_campaign=create_new_credentials_modal) as instructed\n- Replace your credentials and connect."
},
"typeVersion": 1
},
{
"id": "e6b0b88b-7ef1-4b21-8ebe-8931ddf4950a",
"name": "Correspondance Recap Agent",
"type": "@n8n/n8n-nodes-langchain.chainLlm",
"position": [
3056,
448
],
"parameters": {
"text": "=from: {{ $json.from }}\nto: {{ $json.to }}\ndate: {{ $json.date }}\nsubject: {{ $json.subject }}\ntext:\n{{ $json.text }}",
"messages": {
"messageValues": [
{
"message": "=You are helping the \"to\" user recap the last correspondance they had in this email thread. Summarize succiently what was discussed, changed or agreed to help the user prepare for their upcoming meeting."
}
]
},
"promptType": "define"
},
"typeVersion": 1.4
},
{
"id": "0ac9b108-f514-4b60-97c5-b2161dc3b95a",
"name": "Attendee Research Agent",
"type": "@n8n/n8n-nodes-langchain.chainLlm",
"position": [
3760,
448
],
"parameters": {
"text": "=meeting date: {{ $('Check For Upcoming Meetings').item.json.start.dateTime }}\nmeeting url: {{ $('Check For Upcoming Meetings').item.json.hangoutLink }}\nmeeting summary: {{ $('Check For Upcoming Meetings').first().json.summary }}\nmeeting description: {{ $('Check For Upcoming Meetings').item.json.description }}\nmeeting with: {{ $('Check For Upcoming Meetings').item.json.attendees.filter(item => !item.organizer).map(item => item.email).join(',') }}\n\n---\n\n{{\n $('Check For Upcoming Meetings').item.json.attendees.filter(item => !item.organizer).map(item => {\n return `attendee name: ${item.email}\n ${item.email}'s last correspondance: ${ $json.email_summary.replaceAll('\\n', ' ') || `We have not had any correspondance with ${item.email}`}\n `\n }).join('\\n---\\n')\n}}",
"messages": {
"messageValues": [
{
"message": "=You are a personal meeing assistant.\nYou are helping to remind user of an upcoming meeting with {{ $('Check For Upcoming Meetings').item.json.attendees.filter(item => !item.organizer).map(item => item.email).join(',') }} (aka \"the attendee(s)\"}. You will structure your notification using the following guidance:\n1. Start by providing the meeting summary, mentioning the date, with whom and providing the meeting link.\n2. For each attendee, give a short bullet point summary of their last correspondance. Assess if the correspondance has any relevance to the meeting and if so, identify any important todos or items which should be mentioned during the meeting. Additionally, give a short bullet point summary of attendee's recent activity which makes for good talking points. These need not be relevant to the meeting.\n\nWrite your response in a casual tone as if sending a SMS message to the user. \nFormat the answer using basic Markdown (ex: Use * instead of ** for titles and bold).\nUSe bullet points where appropriate."
}
]
},
"promptType": "define"
},
"typeVersion": 1.4
},
{
"id": "bf35b34c-df5b-48f1-9f47-e58da2d4f576",
"name": "OpenAI Model",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
1248,
688
],
"parameters": {
"options": {}
},
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "5fd4f98d-4d0f-4bbe-8652-c499f96eb327",
"name": "Send a message",
"type": "n8n-nodes-base.slack",
"position": [
4320,
448
],
"parameters": {
"text": "={{ $json.text }}",
"user": {
"__rl": true,
"mode": "list",
"value": "U09C3LU03EX",
"cachedResultName": "satoshi.nguyenviet"
},
"select": "user",
"otherOptions": {}
},
"credentials": {
"slackApi": {
"name": "<your credential>"
}
},
"typeVersion": 2.3
},
{
"id": "82e1eb7a-ffcf-4519-8120-b0ad3fd9c150",
"name": "OpenAI Model3",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
3760,
688
],
"parameters": {
"options": {}
},
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "2416c768-83fb-44c7-a731-1fd1fcaa5015",
"name": "OpenAI Model2",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
3056,
688
],
"parameters": {
"options": {}
},
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "2a1cf206-9e4f-44ca-9e40-ab63d221dd34",
"name": "Return Email Error",
"type": "n8n-nodes-base.set",
"position": [
2064,
672
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "9a7efc9e-26b0-48c9-83aa-ae989f20b1df",
"name": "email_summary",
"type": "string",
"value": "No correspondance found."
}
]
}
},
"typeVersion": 3.4
},
{
"id": "f3c9b550-5a78-4c59-93d1-cb2f56e8f600",
"name": "Return Email Error2",
"type": "n8n-nodes-base.set",
"position": [
2576,
672
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "9a7efc9e-26b0-48c9-83aa-ae989f20b1df",
"name": "email_summary",
"type": "string",
"value": "No correspondance found."
}
]
}
},
"typeVersion": 3.4
}
],
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "76837561-081a-4ae4-9dd0-0a6a6f56bedd",
"connections": {
"Has Emails?": {
"main": [
[
{
"node": "Get Message Contents",
"type": "main",
"index": 0
}
],
[
{
"node": "Return Email Error2",
"type": "main",
"index": 0
}
]
]
},
"OpenAI Model": {
"ai_languageModel": [
[
{
"node": "Extract Attendee Information",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"OpenAI Model2": {
"ai_languageModel": [
[
{
"node": "Correspondance Recap Agent",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"OpenAI Model3": {
"ai_languageModel": [
[
{
"node": "Attendee Research Agent",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Simplify Emails": {
"main": [
[
{
"node": "Correspondance Recap Agent",
"type": "main",
"index": 0
}
]
]
},
"Schedule Trigger": {
"main": [
[
{
"node": "Check For Upcoming Meetings",
"type": "main",
"index": 0
}
]
]
},
"Attendees to List": {
"main": [
[
{
"node": "Has Email Address?",
"type": "main",
"index": 0
}
]
]
},
"Has Email Address?": {
"main": [
[
{
"node": "Get Last Correspondence",
"type": "main",
"index": 0
}
],
[
{
"node": "Return Email Error",
"type": "main",
"index": 0
}
]
]
},
"Get Message Contents": {
"main": [
[
{
"node": "Simplify Emails",
"type": "main",
"index": 0
}
]
]
},
"Return Email Success": {
"main": [
[
{
"node": "Attendee Research Agent",
"type": "main",
"index": 0
}
]
]
},
"Attendee Research Agent": {
"main": [
[
{
"node": "Send a message",
"type": "main",
"index": 0
}
]
]
},
"Get Last Correspondence": {
"main": [
[
{
"node": "Has Emails?",
"type": "main",
"index": 0
}
]
]
},
"Correspondance Recap Agent": {
"main": [
[
{
"node": "Return Email Success",
"type": "main",
"index": 0
}
]
]
},
"Check For Upcoming Meetings": {
"main": [
[
{
"node": "Extract Attendee Information",
"type": "main",
"index": 0
}
]
]
},
"Extract Attendee Information": {
"main": [
[
{
"node": "Attendees to List",
"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.
gmailOAuth2googleCalendarOAuth2ApiopenAiApislackApi
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
This workflow builds an AI meeting assistant who sends information-dense pre-meeting notifications for a user's upcoming meetings. A scheduled trigger fires hourly and checks for upcoming meetings within the hour. When found, a search for last correspondence + recent activity is…
Source: https://n8n.io/workflows/11148/ — 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.
This n8n-powered workflow automates the entire lifecycle of real estate lead intake, qualification, routing, assignment, and reporting across multiple channels. It brings WhatsApp inquiries and websit
My workflow 14. Uses rssFeedRead, chainLlm, lmChatOpenAi, openWeatherMap. Scheduled trigger; 40 nodes.
This workflow automatically monitors your Shopify inventory, detects low-stock products, generates smart alert messages, logs records in Google Sheets and sends priority-based notifications to Slack.
Ensure suppliers never miss a follow-up by automating overdue purchase order tracking and scheduling. 📦⏰ This workflow checks Airtable every weekday morning for open POs older than seven days without
Author: Hyrum Hurst, AI Automation Engineer at QuarterSmart Contact: hyrum@quartersmart.com