This workflow corresponds to n8n.io template #12948 — we link there as the canonical source.
This workflow follows the Emailsend → Google Sheets 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": "Y1n7DfPQMf6kT4Hc",
"meta": {
"templateCredsSetupCompleted": true
},
"name": "AI-Powered Guest Pre-Arrival Experience Automation using OpenAI, Google Sheets & Slack",
"tags": [],
"nodes": [
{
"id": "9a2106b5-c91b-4f2a-8ef8-21f11461b74e",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
0,
864
],
"parameters": {
"width": 738,
"height": 510,
"content": "## \ud83c\udfe8 AI-Powered Guest Pre-Arrival Experience Automation using OpenAI, Google Sheets & Slack\n\n### How it works\nThis workflow manages hotel guest profiles and sends personalized pre-arrival messages. It runs daily to check for upcoming check-ins, merges repeat guest data with new reservations, and automatically sends AI-generated welcome messages 2 days before arrival. Messages acknowledge room preferences, dietary restrictions, and special occasions to create a premium hospitality experience.\n\n### Setup steps\n1. Connect Google Sheets with guest data (Sheet1: profiles, Sheet2: updates, Sheet3: message log)\n2. Add OpenAI API credentials for message generation\n3. Configure Slack workspace and Email SMTP for notifications\n4. Set schedule trigger interval (recommended: daily at 9 AM)\n5. Test with sample guest data before going live\n\n**Use case:** Perfect for boutique hotels, resorts, or property managers who want to automate personalized guest communication while maintaining a luxury touch."
},
"typeVersion": 1
},
{
"id": "c7b0ee5d-6945-413a-8b17-74844b99914f",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
848,
1312
],
"parameters": {
"color": 7,
"width": 416,
"height": 404,
"content": "## \ud83d\udcc5 Scheduled Data Retrieval\n\nRuns daily to fetch all guest reservations from Google Sheets. The sheet contains guest profiles with contact info, preferences, allergies, and check-in dates.\n\nSheet1 stores master guest data that gets checked for existing profiles."
},
"typeVersion": 1
},
{
"id": "9fbc1e1e-2688-44a5-8d23-dd307ec1764d",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
1296,
1248
],
"parameters": {
"color": 7,
"width": 636,
"height": 648,
"content": "## \ud83d\udc64 Smart Profile Management\n\nChecks if the guest has stayed before (existing guest_id). Returning guests get their profiles merged \u2014 combining new preferences with historical data like visit count and previous allergies. New guests get a fresh profile created with visit_count set to 1."
},
"typeVersion": 1
},
{
"id": "826ac01d-36cc-41c9-b1b0-45105f749757",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
1952,
1280
],
"parameters": {
"color": 7,
"width": 428,
"height": 516,
"content": "## \u23f0 Pre-Arrival Window Detection\n\nCalculates days remaining until check-in and filters for guests arriving within 2 days. Only those within the window proceed to message generation, preventing spam."
},
"typeVersion": 1
},
{
"id": "0b555a00-2c42-4ae3-abef-8f181cdc083b",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
2400,
1280
],
"parameters": {
"color": 7,
"width": 280,
"height": 504,
"content": "## \ud83e\udd16 AI Message Personalization\n\nGenerates warm, context-aware welcome messages using OpenAI. The prompt includes guest name, room preference, dietary needs, special occasions, and visit history to create natural, premium-sounding messages without being robotic."
},
"typeVersion": 1
},
{
"id": "51141e51-a832-4c20-a989-0453e50e339c",
"name": "Sticky Note5",
"type": "n8n-nodes-base.stickyNote",
"position": [
2704,
1168
],
"parameters": {
"color": 7,
"width": 516,
"height": 828,
"content": "## \ud83d\udcec Multi-Channel Delivery\n\nRoutes messages based on available contact info. If phone number exists, sends via Slack and logs to Sheet3. Otherwise, falls back to email. This ensures every guest receives their personalized message through the best available channel."
},
"typeVersion": 1
},
{
"id": "031ad87f-d70d-4fa7-99f7-e2405b10274c",
"name": "Sticky Note6",
"type": "n8n-nodes-base.stickyNote",
"position": [
880,
1984
],
"parameters": {
"color": 7,
"width": 492,
"height": 400,
"content": "## \u26a0\ufe0f Error Monitoring\n\nCatches any workflow failures and sends alerts to Slack's general-information channel. Helps maintain reliability and enables quick troubleshooting."
},
"typeVersion": 1
},
{
"id": "fa4c768c-8190-42c7-9634-bb46a053b97b",
"name": "Sticky Note7",
"type": "n8n-nodes-base.stickyNote",
"position": [
3248,
1568
],
"parameters": {
"color": 3,
"width": 400,
"height": 268,
"content": "## \ud83d\udd10 Required Credentials\n\n- Google Sheets OAuth2 (read/write access)\n- OpenAI API key (GPT models)\n- Slack workspace token\n- SMTP email credentials\n\nReplace all example emails and IDs with your own before deployment."
},
"typeVersion": 1
},
{
"id": "2b46b385-9eab-457c-bc4f-b3227407bdf1",
"name": "Guest Exists?",
"type": "n8n-nodes-base.if",
"position": [
1344,
1552
],
"parameters": {
"conditions": {
"string": [
{
"value1": "={{ $json.guest_id }}",
"operation": "isNotEmpty"
}
]
}
},
"typeVersion": 1
},
{
"id": "0fb67aae-38de-4349-a014-7b5f32ff1608",
"name": "Merge Returning Guest Data",
"type": "n8n-nodes-base.function",
"position": [
1568,
1456
],
"parameters": {
"functionCode": "const incoming = $input.first().json;\nconst existing = $('Fetch Guest Profiles').first().json;\n\nconst existingAllergies = existing.food_allergies || [];\nconst newAllergies = incoming.food_allergies || [];\nconst mergedAllergies = [...new Set([...existingAllergies, ...newAllergies])];\n\nconst updatedProfile = {\n guest_key: incoming.guest_key,\n guest_id: incoming.guest_id || existing.guest_id,\n name: incoming.name || existing.name,\n email: incoming.email || existing.email,\n phone: incoming.phone || existing.phone,\n room_preference: incoming.room_preference || existing.room_preference,\n food_allergies: mergedAllergies,\n special_occasion: incoming.special_occasion || existing.special_occasion,\n check_in_date: incoming.check_in_date,\n visit_count: (existing.visit_count || 0) + 1,\n last_visit_date: new Date().toISOString(),\n profile_id: existing.id\n};\n\nreturn { json: updatedProfile };"
},
"typeVersion": 1
},
{
"id": "510c6693-3212-48b2-8d86-45d88882e89e",
"name": "Create First-Time Guest Profile",
"type": "n8n-nodes-base.function",
"position": [
1568,
1648
],
"parameters": {
"functionCode": "const incoming = $input.first().json;\n\nconst newProfile = {\n guest_key: incoming.guest_key,\n guest_id: incoming.guest_id,\n name: incoming.name,\n email: incoming.email,\n phone: incoming.phone,\n room_preference: incoming.room_preference,\n food_allergies: incoming.food_allergies || [],\n special_occasion: incoming.special_occasion,\n check_in_date: incoming.check_in_date,\n visit_count: 1,\n last_visit_date: new Date().toISOString(),\n created_at: new Date().toISOString()\n};\n\nreturn { json: newProfile };"
},
"typeVersion": 1
},
{
"id": "c6f57f00-ee0e-4b2a-b900-a7631dfadffa",
"name": "Calculate Days Until Check-In",
"type": "n8n-nodes-base.function",
"position": [
2016,
1552
],
"parameters": {
"functionCode": "const checkInDate = new Date($json.check_in_date);\nconst now = new Date();\nconst diffTime = checkInDate - now;\nconst diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24));\n\nreturn {\n json: {\n ...($json),\n days_until_checkin: diffDays,\n within_window: diffDays <= 2 && diffDays >= 0\n }\n};"
},
"typeVersion": 1
},
{
"id": "e838ef49-240f-4608-ab15-7870ab7bff37",
"name": "Within 2-Day Window?",
"type": "n8n-nodes-base.if",
"position": [
2240,
1552
],
"parameters": {
"conditions": {
"boolean": [
{
"value1": "={{$json.within_window}}",
"value2": true
}
]
}
},
"typeVersion": 1
},
{
"id": "8c4608a4-a60c-4191-bd09-0692096c27a6",
"name": "Generate Personalized Welcome Message",
"type": "n8n-nodes-base.openAi",
"position": [
2480,
1552
],
"parameters": {
"prompt": "=You are a hospitality concierge assistant for a premium hotel.\n\nWrite a short, warm, and personalized pre-arrival message for the guest.\n\nGuest details:\n- Name: {{$json.name}}\n- Room preference: {{$json.room_preference}}\n- Food allergies: {{$json.food_allergies.join(\", \")}}\n- Special occasion: {{$json.special_occasion}}\n- Visit count: {{$json.visit_count}}\n\nRules:\n- If room preference exists, mention it naturally.\n- If food allergies exist, politely acknowledge they have been noted.\n- If a special occasion exists, congratulate or acknowledge it warmly.\n- Keep the tone friendly, premium, and welcoming.\n- Length: 2\u20134 short sentences.\n- Do NOT mention internal systems, visit counts, or data sources.\n- Do NOT use emojis.\n- Do NOT ask questions.\n- End with a positive welcoming line.\n\nOutput ONLY the message text.\n",
"options": {},
"requestOptions": {}
},
"credentials": {
"openAiApi": {
"name": "<your credential>"
}
},
"typeVersion": 1
},
{
"id": "a89960f4-b813-4529-a151-7c008542f1f2",
"name": "Check Message Generated",
"type": "n8n-nodes-base.if",
"position": [
2736,
1552
],
"parameters": {
"conditions": {
"string": [
{
"value1": "={{ $json.text }}",
"operation": "isNotEmpty"
}
]
}
},
"typeVersion": 1
},
{
"id": "ecc7fee8-0d7d-450b-bfb4-1ca9a05f5b25",
"name": "Send Welcome Email",
"type": "n8n-nodes-base.emailSend",
"position": [
2960,
1744
],
"parameters": {
"text": "={{ $('Generate Personalized Welcome Message').item.json.text }}",
"options": {},
"subject": "Your Upcoming Stay - We're Ready for You!",
"toEmail": "={{$json.email}}",
"fromEmail": "user@example.com"
},
"credentials": {
"smtp": {
"name": "<your credential>"
}
},
"typeVersion": 2
},
{
"id": "a7cbb5df-9fea-4864-bc1e-dd4da8a2e84d",
"name": "Error Trigger",
"type": "n8n-nodes-base.errorTrigger",
"position": [
944,
2176
],
"parameters": {},
"typeVersion": 1
},
{
"id": "3253626b-141e-468f-9477-86763ab4d586",
"name": "Fetch Guest Profiles",
"type": "n8n-nodes-base.googleSheets",
"position": [
1120,
1552
],
"parameters": {
"options": {},
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/[YOUR_SPREADSHEET_ID]/edit#gid=0",
"cachedResultName": "Sheet1"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "[YOUR_SPREADSHEET_ID]",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/[YOUR_SPREADSHEET_ID]/edit",
"cachedResultName": "Guest Database"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
},
{
"id": "dd75cf6f-7a2e-41bf-acca-582e02f773d5",
"name": "Daily Check Schedule",
"type": "n8n-nodes-base.scheduleTrigger",
"position": [
896,
1552
],
"parameters": {
"rule": {
"interval": [
{}
]
}
},
"typeVersion": 1.3
},
{
"id": "2675403a-de2a-4290-b069-314536b63a98",
"name": "Save Updated Profile",
"type": "n8n-nodes-base.googleSheets",
"position": [
1792,
1552
],
"parameters": {
"columns": {
"value": {},
"schema": [],
"mappingMode": "autoMapInputData",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "appendOrUpdate",
"sheetName": {
"__rl": true,
"mode": "list",
"value": 254632980,
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/[YOUR_SPREADSHEET_ID]/edit#gid=254632980",
"cachedResultName": "Sheet2"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "[YOUR_SPREADSHEET_ID]",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/[YOUR_SPREADSHEET_ID]/edit",
"cachedResultName": "Guest Database"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
},
{
"id": "c6eddf59-9708-48ec-9c70-a806707858b7",
"name": "Send Slack Notification",
"type": "n8n-nodes-base.slack",
"position": [
2960,
1360
],
"parameters": {
"text": "={{ $json.text }}",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "list",
"value": "C09GNB90TED",
"cachedResultName": "guest-notifications"
},
"otherOptions": {}
},
"credentials": {
"slackApi": {
"name": "<your credential>"
}
},
"typeVersion": 2.4
},
{
"id": "8accf523-9b18-441e-8b82-55dbcd301867",
"name": "Log Message to Sheet",
"type": "n8n-nodes-base.googleSheets",
"position": [
2960,
1552
],
"parameters": {
"columns": {
"value": {},
"schema": [
{
"id": "text",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "text",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "index",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "index",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "logprobs",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "logprobs",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "finish_reason",
"type": "string",
"display": true,
"removed": false,
"required": false,
"displayName": "finish_reason",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "autoMapInputData",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "appendOrUpdate",
"sheetName": {
"__rl": true,
"mode": "list",
"value": 369348291,
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/[YOUR_SPREADSHEET_ID]/edit#gid=369348291",
"cachedResultName": "Sheet3"
},
"documentId": {
"__rl": true,
"mode": "list",
"value": "[YOUR_SPREADSHEET_ID]",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/[YOUR_SPREADSHEET_ID]/edit",
"cachedResultName": "Guest Database"
}
},
"credentials": {
"googleSheetsOAuth2Api": {
"name": "<your credential>"
}
},
"typeVersion": 4.7
},
{
"id": "b0c619f9-5d1b-4c2a-939a-697fb72977db",
"name": "Alert on Workflow Failure",
"type": "n8n-nodes-base.slack",
"position": [
1200,
2176
],
"parameters": {
"text": "\u26a0\ufe0f Hotel Pre-Arrival Workflow Error Detected\n\nPlease check the execution log for details.",
"select": "channel",
"channelId": {
"__rl": true,
"mode": "list",
"value": "C09GNB90TED",
"cachedResultName": "workflow-errors"
},
"otherOptions": {}
},
"credentials": {
"slackApi": {
"name": "<your credential>"
}
},
"typeVersion": 2.4
}
],
"active": false,
"settings": {
"executionOrder": "v1"
},
"versionId": "596eab85-c6a5-46ee-9928-e01489bfe49d",
"connections": {
"Error Trigger": {
"main": [
[
{
"node": "Alert on Workflow Failure",
"type": "main",
"index": 0
}
]
]
},
"Guest Exists?": {
"main": [
[
{
"node": "Merge Returning Guest Data",
"type": "main",
"index": 0
}
],
[
{
"node": "Create First-Time Guest Profile",
"type": "main",
"index": 0
}
]
]
},
"Daily Check Schedule": {
"main": [
[
{
"node": "Fetch Guest Profiles",
"type": "main",
"index": 0
}
]
]
},
"Fetch Guest Profiles": {
"main": [
[
{
"node": "Guest Exists?",
"type": "main",
"index": 0
}
]
]
},
"Save Updated Profile": {
"main": [
[
{
"node": "Calculate Days Until Check-In",
"type": "main",
"index": 0
}
]
]
},
"Within 2-Day Window?": {
"main": [
[],
[
{
"node": "Generate Personalized Welcome Message",
"type": "main",
"index": 0
}
]
]
},
"Check Message Generated": {
"main": [
[
{
"node": "Send Slack Notification",
"type": "main",
"index": 0
},
{
"node": "Log Message to Sheet",
"type": "main",
"index": 0
}
],
[
{
"node": "Send Welcome Email",
"type": "main",
"index": 0
}
]
]
},
"Merge Returning Guest Data": {
"main": [
[
{
"node": "Save Updated Profile",
"type": "main",
"index": 0
}
]
]
},
"Calculate Days Until Check-In": {
"main": [
[
{
"node": "Within 2-Day Window?",
"type": "main",
"index": 0
}
]
]
},
"Create First-Time Guest Profile": {
"main": [
[
{
"node": "Save Updated Profile",
"type": "main",
"index": 0
}
]
]
},
"Generate Personalized Welcome Message": {
"main": [
[
{
"node": "Check Message Generated",
"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.
googleSheetsOAuth2ApiopenAiApislackApismtp
For the full experience including quality scoring and batch install features for each workflow upgrade to Pro
About this workflow
Description This workflow automates a personalized pre-arrival guest experience for hotels by combining Google Sheets, OpenAI, Email, and Slack. It detects upcoming check-ins, maintains unified guest profiles for new and returning guests, and sends warm, AI-generated welcome…
Source: https://n8n.io/workflows/12948/ — 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.
Complete AI-powered sales system Automates lead capture, qualification, and follow-up from multiple channels. AI INTELLIGENCE:
Businesses using Jotform to collect customer feedback who want to automate sentiment analysis, email responses, and internal reporting — especially eCommerce, support, or CX teams looking to scale wit
Consultants, agencies, freelancers, and professional service firms who need to create customized proposals and contracts quickly and efficiently.
This workflow automates guest upsell discovery and recommendation for hotels by combining Google Sheets, OpenAI, and Slack. It is designed to help hospitality teams proactively identify the single bes
Grain Real Estate Land Showcase v1. Uses formTrigger, httpRequest, openAi, emailSend. Event-driven trigger; 13 nodes.