使用GPT-4o-mini自动化从Gmail到Google Sheets的酒店预订请求
高级
这是一个Document Extraction, AI Summarization领域的自动化工作流,包含 29 个节点。主要使用 If, Set, Code, Gmail, Filter 等节点。 通过GPT-4o-mini将Gmail中的酒店预订请求自动录入Google Sheets
前置要求
- •Google 账号和 Gmail API 凭证
- •Google Sheets API 凭证
- •OpenAI API Key
工作流预览
可视化展示节点连接关系,支持缩放和平移
导出工作流
复制以下 JSON 配置到 n8n 导入,即可使用此工作流
{
"meta": {
"instanceId": "9229062b09b690c4ccf0cfe4e3838e59180e8646ff632ec42c3b984a473da8ae"
},
"nodes": [
{
"id": "13cf7be4-2d3e-4e58-b4d7-409f107197c1",
"name": "便签说明5",
"type": "n8n-nodes-base.stickyNote",
"position": [
80,
1056
],
"parameters": {
"color": 2,
"width": 528,
"height": 976,
"content": "## 错误通知"
},
"typeVersion": 1
},
{
"id": "bc3df21f-0a08-49dd-aab6-4f1b0452c252",
"name": "便签说明4",
"type": "n8n-nodes-base.stickyNote",
"position": [
0,
0
],
"parameters": {
"color": 3,
"width": 464,
"height": 592,
"content": "## 确认电子邮件"
},
"typeVersion": 1
},
{
"id": "1d59ebc0-245d-4b58-b8a1-ec396761f5c5",
"name": "便签3",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1344,
336
],
"parameters": {
"color": 7,
"width": 256,
"height": 304,
"content": "### 3. 工作流配置"
},
"typeVersion": 1
},
{
"id": "16372fd9-9526-454e-8c86-e8e2156e9aea",
"name": "用于电子邮件文本的 OpenAI 模型",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
-1504,
1200
],
"parameters": {
"text": "={{ $('Get many messages (1)').item.json.text }}",
"options": {
"systemMessage": "You are a hotel booking specialist AI. Extract booking information from emails and return ONLY a valid JSON object.\n\nCRITICAL INSTRUCTIONS:\n1. Look for booking details anywhere in the email text\n2. Extract numbers from phrases like \"55 rooms\" or \"Number of Rooms: 55\"\n3. Parse dates in any format and convert to YYYY-MM-DD\n4. If a field is not found, use null\n5. Return ONLY the JSON object - no explanations\n\nREQUIRED JSON STRUCTURE:\n{\n \"travel_agency_name\": \"string or null\",\n \"contact_person\": \"string or null\",\n \"contact_email\": \"string or null\",\n \"contact_phone\": \"string or null\",\n \"number_of_rooms\": number,\n \"check_in_date\": \"YYYY-MM-DD or null\",\n \"check_out_date\": \"YYYY-MM-DD or null\",\n \"room_type\": \"string or null\",\n \"special_requests\": \"string or null\",\n \"total_guests\": number,\n \"booking_reference\": \"string or null\",\n \"urgency\": \"urgent or normal or low\"\n}"
},
"promptType": "define",
"hasOutputParser": true
},
"typeVersion": 1.9,
"continueOnFail": true
},
{
"id": "64a15364-f803-41bf-a4db-88fdda710e60",
"name": "用于 PDF 的 OpenAI 模型",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
-1504,
848
],
"parameters": {
"text": "={{ $json.text }}",
"options": {
"systemMessage": "You are a hotel booking specialist AI. Extract booking information from the PDF attachment and return ONLY a valid JSON object.\n\nCRITICAL INSTRUCTIONS:\n1. Look for booking details anywhere in the document\n2. Extract numbers from phrases like \"55 rooms\" or \"Number of Rooms: 55\"\n3. Parse dates in any format and convert to YYYY-MM-DD\n4. If a field is not found, use null\n5. Return ONLY the JSON object - no explanations\n\nREQUIRED JSON STRUCTURE:\n{\n \"travel_agency_name\": \"string or null\",\n \"contact_person\": \"string or null\",\n \"contact_email\": \"string or null\",\n \"contact_phone\": \"string or null\",\n \"number_of_rooms\": number,\n \"check_in_date\": \"YYYY-MM-DD or null\",\n \"check_out_date\": \"YYYY-MM-DD or null\",\n \"room_type\": \"string or null\",\n \"special_requests\": \"string or null\",\n \"total_guests\": number,\n \"booking_reference\": \"string or null\",\n \"urgency\": \"urgent or normal or low\"\n}"
},
"promptType": "define",
"hasOutputParser": true
},
"typeVersion": 1.9,
"continueOnFail": true
},
{
"id": "dae2d85e-4b36-4520-a89d-d2509688dcb1",
"name": "OpenAI GPT 模型(电子邮件)",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
-1504,
1344
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "gpt-4o-mini"
},
"options": {
"temperature": 0.3,
"responseFormat": "json_object"
}
},
"typeVersion": 1.2
},
{
"id": "43353dbd-5112-44e4-ac85-331f7612e359",
"name": "OpenAI GPT 模型(附件)",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
-1504,
976
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "gpt-4o-mini"
},
"options": {
"temperature": 0.3,
"responseFormat": "json_object"
}
},
"typeVersion": 1.2
},
{
"id": "6ebca2d8-b73d-4ec8-8546-f48083fbc135",
"name": "记录成功指标",
"type": "n8n-nodes-base.googleSheets",
"position": [
608,
672
],
"parameters": {
"columns": {
"value": {
"case_id": "={{ $('Apply Business Rules').item.json.case_id }}",
"priority": "={{ $('Apply Business Rules').item.json.priority }}",
"timestamp": "={{ $today }}",
"email_sent": "={{ $('Send Confirmation Email').item.json.error ? 'No' : 'Yes' }}",
"assigned_team": "={{ $('Apply Business Rules').item.json.assigned_team }}",
"sheets_updated": "Yes",
"number_of_rooms": "={{ $('Apply Business Rules').item.json.number_of_rooms }}",
"processing_time_seconds": "={{ Math.round(($execution.startedAt ? (Date.now() - new Date($execution.startedAt).getTime()) / 1000 : 0)) }}"
},
"schema": [
{
"id": "timestamp",
"type": "string",
"display": true,
"required": false,
"displayName": "timestamp",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "case_id",
"type": "string",
"display": true,
"required": false,
"displayName": "case_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "processing_time_seconds",
"type": "string",
"display": true,
"required": false,
"displayName": "processing_time_seconds",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "assigned_team",
"type": "string",
"display": true,
"required": false,
"displayName": "assigned_team",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "priority",
"type": "string",
"display": true,
"required": false,
"displayName": "priority",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "number_of_rooms",
"type": "string",
"display": true,
"required": false,
"displayName": "number_of_rooms",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "email_sent",
"type": "string",
"display": true,
"required": false,
"displayName": "email_sent",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "sheets_updated",
"type": "string",
"display": true,
"required": false,
"displayName": "sheets_updated",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "name",
"value": "Success Metrics"
},
"documentId": {
"__rl": true,
"mode": "expression",
"value": "={{ $('Configuration: User Settings').item.json.gSheetID }}"
}
},
"typeVersion": 4.5
},
{
"id": "b395a72e-e78d-4200-9e72-130a8e885e41",
"name": "发送确认电子邮件",
"type": "n8n-nodes-base.gmail",
"position": [
240,
672
],
"webhookId": "ad57867a-a7b8-4c06-a446-cb47bc70da57",
"parameters": {
"sendTo": "={{ $json.contact_email }}",
"message": "=<html>\n<body style=\"font-family: Arial, sans-serif; line-height: 1.6; color: #333;\">\n\t<div style=\"max-width: 600px; margin: 0 auto; padding: 20px; border: 1px solid #ddd;\">\n\t\t<h2 style=\"color: #2c3e50; border-bottom: 2px solid #3498db; padding-bottom: 10px;\">Booking Request Confirmation</h2>\n\t\t\n\t\t<p>Dear {{ $json.contact_person }},</p>\n\t\t\n\t\t<p>Thank yourself for your booking request. Your reservation has been received and is being processed by our <strong>{{ $json.assigned_team }}</strong>.</p>\n\t\t\n\t\t<div style=\"background-color: #f8f9fa; padding: 15px; border-radius: 5px; margin: 20px 0;\">\n\t\t\t<h3 style=\"color: #2c3e50; margin-top: 0;\">Booking Details</h3>\n\t\t\t<table style=\"width: 100%; border-collapse: collapse;\">\n\t\t\t\t<tr>\n\t\t\t\t\t<td style=\"padding: 5px 0;\"><strong>Case Reference:</strong></td>\n\t\t\t\t\t<td style=\"padding: 5px 0;\">{{ $json.case_id }}</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td style=\"padding: 5px 0;\"><strong>Priority:</strong></td>\n\t\t\t\t\t<td style=\"padding: 5px 0;\"><span style=\"background-color: #{{ $json.priority === 'High' ? 'e74c3c' : $json.priority === 'Medium' ? 'f39c12' : '27ae60' }}; color: white; padding: 2px 8px; border-radius: 3px;\">{{ $json.priority }}</span></td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td style=\"padding: 5px 0;\"><strong>Number of Rooms:</strong></td>\n\t\t\t\t\t<td style=\"padding: 5px 0;\">{{ $json.number_of_rooms }}</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td style=\"padding: 5px 0;\"><strong>Check-in Date:</strong></td>\n\t\t\t\t\t<td style=\"padding: 5px 0;\">{{ $json.check_in_date }}</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td style=\"padding: 5px 0;\"><strong>Check-out Date:</strong></td>\n\t\t\t\t\t<td style=\"padding: 5px 0;\">{{ $json.check_out_date }}</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td style=\"padding: 5px 0;\"><strong>Total Nights:</strong></td>\n\t\t\t\t\t<td style=\"padding: 5px 0;\">{{ $json.total_nights }}</td>\n\t\t\t\t</tr>\n\t\t\t\t<tr>\n\t\t\t\t\t<td style=\"padding: 5px 0;\"><strong>Total Guests:</strong></td>\n\t\t\t\t\t<td style=\"padding: 5px 0;\">{{ $json.total_guests }}</td>\n\t\t\t\t</tr>\n\t\t\t</table>\n\t\t</div>\n\t\t\n\t\t<p><strong>Status:</strong> {{ $json.status }}</p>\n\t\t<p><strong>Booking Reference:</strong> {{ $json.booking_reference }}</p>\n\t\t\n\t\t<p style=\"margin-top: 20px;\">Our team will review your request and respond within <strong>24 hours</strong>.</p>\n\t\t\n\t\t<p>If you have any questions, please contact us at {{ $json.team_email }}</p>\n\t\t\n\t\t<p style=\"margin-top: 30px;\">Best regards,<br>\n\t\t<strong>Hotel Booking Team</strong></p>\n\t</div>\n</body>\n</html>",
"options": {
"appendAttribution": false
},
"subject": "=Booking Request Received - Ref #{{ $json.case_id }}"
},
"typeVersion": 2.1,
"continueOnFail": true
},
{
"id": "b3f06fe6-b8db-4828-a6b9-a7b8cc13ea02",
"name": "记录团队分配",
"type": "n8n-nodes-base.googleSheets",
"position": [
-16,
864
],
"parameters": {
"columns": {
"value": {
"case_id": "={{ $json.case_id }}",
"priority": "={{ $json.priority }}",
"timestamp": "={{ $json.processed_date }}",
"team_email": "={{ $json.team_email }}",
"assigned_team": "={{ $json.assigned_team }}",
"check_in_date": "={{ $json.check_in_date }}",
"travel_agency": "={{ $json.travel_agency_name }}",
"number_of_rooms": "={{ $json.number_of_rooms }}"
},
"schema": [
{
"id": "timestamp",
"type": "string",
"display": true,
"required": false,
"displayName": "timestamp",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "case_id",
"type": "string",
"display": true,
"required": false,
"displayName": "case_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "assigned_team",
"type": "string",
"display": true,
"required": false,
"displayName": "assigned_team",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "team_email",
"type": "string",
"display": true,
"required": false,
"displayName": "team_email",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "priority",
"type": "string",
"display": true,
"required": false,
"displayName": "priority",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "number_of_rooms",
"type": "string",
"display": true,
"required": false,
"displayName": "number_of_rooms",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "travel_agency",
"type": "string",
"display": true,
"required": false,
"displayName": "travel_agency",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "check_in_date",
"type": "string",
"display": true,
"required": false,
"displayName": "check_in_date",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "list",
"value": 1858323773,
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1qhUoE4baN5TyO51mD2caYU789XizhXl3UDCCT0v83So/edit#gid=1858323773",
"cachedResultName": "Team Assignments"
},
"documentId": {
"__rl": true,
"mode": "expression",
"value": "={{ $('Configuration: User Settings').item.json.gSheetID }}"
}
},
"typeVersion": 4.5,
"continueOnFail": true
},
{
"id": "c49c023b-71b2-474f-a2ab-2444a3d4cc63",
"name": "追加到案例表格",
"type": "n8n-nodes-base.googleSheets",
"position": [
-16,
672
],
"parameters": {
"columns": {
"value": {
"status": "={{ $json.status }}",
"case_id": "={{ $json.case_id }}",
"urgency": "={{ $json.urgency }}",
"priority": "={{ $json.priority }}",
"room_type": "={{ $json.room_type }}",
"team_email": "={{ $json.team_email }}",
"total_guests": "={{ $json.total_guests }}",
"total_nights": "={{ $json.total_nights }}",
"assigned_team": "={{ $json.assigned_team }}",
"check_in_date": "={{ $json.check_in_date }}",
"contact_email": "={{ $json.contact_email }}",
"contact_phone": "={{ $json.contact_phone }}",
"check_out_date": "={{ $json.check_out_date }}",
"contact_person": "={{ $json.contact_person }}",
"processed_date": "={{ $json.processed_date }}",
"number_of_rooms": "={{ $json.number_of_rooms }}",
"original_sender": "={{ $('Get many messages (1)').item.json.from.value[0].address }}",
"original_subject": "={{ $('Look for incoming emails').item.json.Subject }}",
"special_requests": "={{ $json.special_requests }}",
"booking_reference": "={{ $json.booking_reference }}",
"days_until_checkin": "={{ $json.days_until_checkin }}",
"travel_agency_name": "={{ $json.travel_agency_name }}"
},
"schema": [
{
"id": "case_id",
"type": "string",
"display": true,
"required": false,
"displayName": "case_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "processed_date",
"type": "string",
"display": true,
"required": false,
"displayName": "processed_date",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "travel_agency_name",
"type": "string",
"display": true,
"required": false,
"displayName": "travel_agency_name",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "contact_person",
"type": "string",
"display": true,
"required": false,
"displayName": "contact_person",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "contact_email",
"type": "string",
"display": true,
"required": false,
"displayName": "contact_email",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "contact_phone",
"type": "string",
"display": true,
"required": false,
"displayName": "contact_phone",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "number_of_rooms",
"type": "string",
"display": true,
"required": false,
"displayName": "number_of_rooms",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "check_in_date",
"type": "string",
"display": true,
"required": false,
"displayName": "check_in_date",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "check_out_date",
"type": "string",
"display": true,
"required": false,
"displayName": "check_out_date",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "total_nights",
"type": "string",
"display": true,
"required": false,
"displayName": "total_nights",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "room_type",
"type": "string",
"display": true,
"required": false,
"displayName": "room_type",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "total_guests",
"type": "string",
"display": true,
"required": false,
"displayName": "total_guests",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "special_requests",
"type": "string",
"display": true,
"required": false,
"displayName": "special_requests",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "booking_reference",
"type": "string",
"display": true,
"required": false,
"displayName": "booking_reference",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "urgency",
"type": "string",
"display": true,
"required": false,
"displayName": "urgency",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "assigned_team",
"type": "string",
"display": true,
"required": false,
"displayName": "assigned_team",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "team_email",
"type": "string",
"display": true,
"required": false,
"displayName": "team_email",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "priority",
"type": "string",
"display": true,
"required": false,
"displayName": "priority",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "status",
"type": "string",
"display": true,
"required": false,
"displayName": "status",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "days_until_checkin",
"type": "string",
"display": true,
"required": false,
"displayName": "days_until_checkin",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "original_sender",
"type": "string",
"display": true,
"required": false,
"displayName": "original_sender",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "original_subject",
"type": "string",
"display": true,
"required": false,
"displayName": "original_subject",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "list",
"value": "gid=0",
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1qhUoE4baN5TyO51mD2caYU789XizhXl3UDCCT0v83So/edit#gid=0",
"cachedResultName": "Cases"
},
"documentId": {
"__rl": true,
"mode": "expression",
"value": "={{ $('Configuration: User Settings').item.json.gSheetID }}"
}
},
"typeVersion": 4.5,
"continueOnFail": true
},
{
"id": "e756d1fe-fb7a-4731-8106-2d58a7141f13",
"name": "应用业务规则",
"type": "n8n-nodes-base.code",
"position": [
-480,
752
],
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "const bookingData = $json.validated_data;\n\nlet assignedTeam = \"\";\nlet teamEmail = \"\";\nlet priority = \"Normal\";\nlet status = \"New\";\n\nconst numRooms = parseInt(bookingData.number_of_rooms) || 0;\n\n// Rule 1: Assignment based on number of rooms\nif (numRooms >= 50) {\n\tassignedTeam = \"Large Bookings Team\";\n\tteamEmail = \"large-bookings@hotel.com\";\n\tpriority = \"High\";\n} else if (numRooms >= 20) {\n\tassignedTeam = \"Group Bookings Team\";\n\tteamEmail = \"group-bookings@hotel.com\";\n\tpriority = \"Medium\";\n} else {\n\tassignedTeam = \"Regular Bookings Team\";\n\tteamEmail = \"regular-bookings@hotel.com\";\n\tpriority = \"Normal\";\n}\n\n// Rule 2: Urgency override\nif (bookingData.urgency === \"urgent\") {\n\tpriority = \"High\";\n\tassignedTeam = \"Urgent Bookings Team\";\n\tteamEmail = \"urgent-bookings@hotel.com\";\n}\n\n// Rule 3: Check-in date proximity\nconst checkInDate = new Date(bookingData.check_in_date);\nconst today = new Date();\nconst daysUntilCheckIn = Math.ceil((checkInDate - today) / (1000 * 60 * 60 * 24));\n\nif (daysUntilCheckIn <= 7 && daysUntilCheckIn >= 0) {\n\tpriority = \"High\";\n\tstatus = \"Urgent - Near Check-in\";\n}\n\n// Rule 4: VIP Agencies\nconst vipAgencies = [\"Premium Travel Co\", \"Elite Bookings\", \"Luxury Tours\"];\nif (vipAgencies.some(agency => bookingData.travel_agency_name?.includes(agency))) {\n\tpriority = \"High\";\n\tassignedTeam = \"VIP Relations Team\";\n\tteamEmail = \"vip-relations@hotel.com\";\n}\n\n// Calculate total nights\nconst checkOutDate = new Date(bookingData.check_out_date);\nconst totalNights = Math.ceil((checkOutDate - checkInDate) / (1000 * 60 * 60 * 24));\n\n// Get original email info - FIXED LINE BELOW\nconst originalEmail = $('Look for incoming emails').item.json;\n\nreturn {\n\tjson: {\n\t\t// Extracted booking data\n\t\ttravel_agency_name: bookingData.travel_agency_name || \"N/A\",\n\t\tcontact_person: bookingData.contact_person || \"N/A\",\n\t\tcontact_email: bookingData.contact_email || \"N/A\",\n\t\tcontact_phone: bookingData.contact_phone || \"N/A\",\n\t\tnumber_of_rooms: numRooms,\n\t\tcheck_in_date: bookingData.check_in_date || \"N/A\",\n\t\tcheck_out_date: bookingData.check_out_date || \"N/A\",\n\t\ttotal_nights: totalNights || 0,\n\t\troom_type: bookingData.room_type || \"Standard\",\n\t\tspecial_requests: bookingData.special_requests || \"None\",\n\t\ttotal_guests: bookingData.total_guests || numRooms * 2,\n\t\tbooking_reference: bookingData.booking_reference || `BK${Date.now()}`,\n\t\turgency: bookingData.urgency || \"normal\",\n\t\t\n\t\t// Business rules output\n\t\tassigned_team: assignedTeam,\n\t\tteam_email: teamEmail,\n\t\tpriority: priority,\n\t\tstatus: status,\n\t\tdays_until_checkin: daysUntilCheckIn,\n\t\t\n\t\t// Metadata\n\t\tprocessed_date: new Date().toISOString(),\n\t\toriginal_subject: originalEmail.subject,\n\t\toriginal_sender: originalEmail.from,\n\t\tcase_id: `CASE-${Date.now()}`,\n\t\tprocessing_status: \"SUCCESS\"\n\t}\n};"
},
"typeVersion": 2,
"continueOnFail": true
},
{
"id": "a76e69e5-2df0-48c1-9cce-522a191e62da",
"name": "发送错误通知",
"type": "n8n-nodes-base.gmail",
"position": [
-144,
1296
],
"webhookId": "814ad124-75bd-4a92-8686-0b3729d263e5",
"parameters": {
"sendTo": "={{ $('Configuration: User Settings').item.json.adminEmailForErrors }}",
"message": "=<html>\n<body style=\"font-family: Arial, sans-serif; line-height: 1.6; color: #333;\">\n\t<div style=\"max-width: 600px; margin: 0 auto; padding: 20px; border: 1px solid #dc3545; border-radius: 5px;\">\n\t\t<h2 style=\"color: #dc3545; border-bottom: 2px solid #dc3545; padding-bottom: 10px;\">⚠️ Booking Processing Error</h2>\n\t\t\n\t\t<div style=\"background-color: #f8d7da; padding: 15px; border-radius: 5px; margin: 20px 0; border-left: 4px solid #dc3545;\">\n\t\t\t<h3 style=\"color: #721c24; margin-top: 0;\">Error Details</h3>\n\t\t\t<p><strong>Error Type:</strong> {{ $json.error_type }}</p>\n\t\t\t<p><strong>Error Message:</strong> {{ $json.error_message }}</p>\n\t\t\t<p><strong>Timestamp:</strong> {{ $json.timestamp }}</p>\n\t\t</div>\n\t\t\n\t\t<div style=\"background-color: #fff3cd; padding: 15px; border-radius: 5px; margin: 20px 0; border-left: 4px solid #ffc107;\">\n\t\t\t<h3 style=\"color: #856404; margin-top: 0;\">Original Email Information</h3>\n\t\t\t<p><strong>From:</strong> {{ $('Get many messages (1)').item.json.from.value[0].address|| 'N/A' }}</p>\n\t\t\t<p><strong>Subject:</strong> {{ $('Get many messages (1)').item.json.subject|| 'N/A' }}</p>\n\t\t\t<p><strong>Date:</strong> {{ $('Get many messages (1)').item.json.headers.date || 'N/A' }}</p>\n\t\t\t<p><strong>Snippet:</strong> {{ $('Look for incoming emails').item.json.snippet|| 'N/A' }}</p>\n\t\t</div>\n\t\t\n\t\t<div style=\"background-color: #d1ecf1; padding: 15px; border-radius: 5px; margin: 20px 0; border-left: 4px solid #17a2b8;\">\n\t\t\t<h3 style=\"color: #0c5460; margin-top: 0;\">Extracted Data (if any)</h3>\n\t\t\t<pre style=\"background-color: white; padding: 10px; border-radius: 3px; overflow-x: auto;\">{{ JSON.stringify($json.extracted_data, null, 2) }}</pre>\n\t\t</div>\n\t\t\n\t\t<div style=\"margin-top: 20px; padding: 15px; background-color: #e7f3ff; border-radius: 5px;\">\n\t\t\t<h3 style=\"color: #004085; margin-top: 0;\">Action Required</h3>\n\t\t\t<p>Please review this email manually and process the booking request.</p>\n\t\t\t<p><strong>Workflow Execution ID:</strong> {{ $execution.id }}</p>\n\t\t</div>\n\t\t\n\t\t<p style=\"margin-top: 30px; font-size: 12px; color: #666;\">This is an automated alert from the Hotel Booking Workflow System.</p>\n\t</div>\n</body>\n</html>",
"options": {
"appendAttribution": false
},
"subject": "=⚠️ Booking Processing Error - {{ $json.error_type }}"
},
"typeVersion": 2.1
},
{
"id": "a47aa97a-decd-4219-9642-c2d6c0e4ef29",
"name": "记录错误到表格",
"type": "n8n-nodes-base.googleSheets",
"position": [
-480,
1296
],
"parameters": {
"columns": {
"value": {
"timestamp": "={{ $json.timestamp }}",
"Error Type": "={{ $json.error_type }}",
"error_type": "={{ $json.error_type }}",
"email_snippet": "={{ $('Look for incoming emails').item.json.snippet }}",
"error_message": "={{ $json.error_message }}",
"extracted_data": "={{ $json.extracted_data }}",
"original_sender": "={{ $('Look for incoming emails').item.json.From }}",
"original_subject": "={{ $('Look for incoming emails').item.json.Subject }}",
"workflow_execution_id": "={{ $workflow.id }}"
},
"schema": [
{
"id": "timestamp",
"type": "string",
"display": true,
"required": false,
"displayName": "timestamp",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "error_type",
"type": "string",
"display": true,
"required": false,
"displayName": "error_type",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "error_message",
"type": "string",
"display": true,
"required": false,
"displayName": "error_message",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "original_subject",
"type": "string",
"display": true,
"required": false,
"displayName": "original_subject",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "original_sender",
"type": "string",
"display": true,
"required": false,
"displayName": "original_sender",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "email_snippet",
"type": "string",
"display": true,
"required": false,
"displayName": "email_snippet",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "extracted_data",
"type": "string",
"display": true,
"required": false,
"displayName": "extracted_data",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "workflow_execution_id",
"type": "string",
"display": true,
"required": false,
"displayName": "workflow_execution_id",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Error Type",
"type": "string",
"display": true,
"required": false,
"displayName": "Error Type",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Meaning",
"type": "string",
"display": true,
"required": false,
"displayName": "Meaning",
"defaultMatch": false,
"canBeUsedToMatch": true
},
{
"id": "Action Needed",
"type": "string",
"display": true,
"required": false,
"displayName": "Action Needed",
"defaultMatch": false,
"canBeUsedToMatch": true
}
],
"mappingMode": "defineBelow",
"matchingColumns": [],
"attemptToConvertTypes": false,
"convertFieldsToString": false
},
"options": {},
"operation": "append",
"sheetName": {
"__rl": true,
"mode": "list",
"value": 325369644,
"cachedResultUrl": "https://docs.google.com/spreadsheets/d/1qhUoE4baN5TyO51mD2caYU789XizhXl3UDCCT0v83So/edit#gid=325369644",
"cachedResultName": "Error Logs"
},
"documentId": {
"__rl": true,
"mode": "expression",
"value": "={{ $('Configuration: User Settings').item.json.gSheetID }}"
}
},
"typeVersion": 4.5
},
{
"id": "4516f99d-9d38-4bb8-8f42-cd1123a0724a",
"name": "检查错误",
"type": "n8n-nodes-base.if",
"position": [
-880,
1024
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"id": "check-error",
"operator": {
"type": "boolean",
"operation": "false"
},
"leftValue": "={{ $json.error_occurred }}",
"rightValue": ""
}
]
},
"looseTypeValidation": true
},
"typeVersion": 2.2
},
{
"id": "48268a8c-9a75-45fb-afbb-c5782d6c8e7b",
"name": "验证提取",
"type": "n8n-nodes-base.code",
"position": [
-1120,
1024
],
"parameters": {
"mode": "runOnceForEachItem",
"jsCode": "// Check if AI extraction succeeded\nif ($json.error) {\n\treturn {\n\t\tjson: {\n\t\t\terror_occurred: true,\n\t\t\terror_type: \"AI_EXTRACTION_FAILED\",\n\t\t\terror_message: $json.error.message || \"AI extraction failed\",\n\t\t\toriginal_email: $('Get many messages (1)').item.json,\n\t\t\ttimestamp: new Date().toISOString()\n\t\t}\n\t};\n}\n\nif (!$json.output) {\n\treturn {\n\t\tjson: {\n\t\t\terror_occurred: true,\n\t\t\terror_type: \"NO_OUTPUT\",\n\t\t\terror_message: \"AI did not return any output\",\n\t\t\toriginal_email: $('Get many messages (1)').item.json,\n\t\t\ttimestamp: new Date().toISOString()\n\t\t}\n\t};\n}\n\ntry {\n\tlet bookingData;\n\t\n\tif (typeof $json.output === 'string') {\n\t\tbookingData = JSON.parse($json.output);\n\t} else {\n\t\tbookingData = $json.output;\n\t}\n\t\n\tconsole.log(\"Parsed booking data:\", JSON.stringify(bookingData, null, 2));\n\t\n\tconst requiredFields = ['travel_agency_name', 'number_of_rooms', 'check_in_date', 'check_out_date'];\n\tconst missingFields = [];\n\t\n\tfor (const field of requiredFields) {\n\t\tif (!bookingData[field] || bookingData[field] === null || bookingData[field] === \"null\" || bookingData[field] === \"\") {\n\t\t\tmissingFields.push(field);\n\t\t}\n\t}\n\t\n\tif (missingFields.length > 0) {\n\t\tconsole.log(\"Missing fields detected:\", missingFields);\n\t\treturn {\n\t\t\tjson: {\n\t\t\t\terror_occurred: true,\n\t\t\t\terror_type: \"MISSING_REQUIRED_FIELDS\",\n\t\t\t\terror_message: `Missing required fields: ${missingFields.join(', ')}`,\n\t\t\t\textracted_data: bookingData,\n\t\t\t\toriginal_email: $('Get many messages (1)').item.json,\n\t\t\t\ttimestamp: new Date().toISOString()\n\t\t\t}\n\t\t};\n\t}\n\t\n\tconst checkInDate = new Date(bookingData.check_in_date);\n\tconst checkOutDate = new Date(bookingData.check_out_date);\n\t\n\tif (isNaN(checkInDate.getTime()) || isNaN(checkOutDate.getTime())) {\n\t\tconsole.log(\"Invalid date format detected\");\n\t\treturn {\n\t\t\tjson: {\n\t\t\t\terror_occurred: true,\n\t\t\t\terror_type: \"INVALID_DATE_FORMAT\",\n\t\t\t\terror_message: \"Check-in or check-out date is invalid\",\n\t\t\t\textracted_data: bookingData,\n\t\t\t\toriginal_email: $('Get many messages (1)').item.json,\n\t\t\t\ttimestamp: new Date().toISOString()\n\t\t\t}\n\t\t};\n\t}\n\t\n\tif (checkOutDate <= checkInDate) {\n\t\tconsole.log(\"Date logic error detected\");\n\t\treturn {\n\t\t\tjson: {\n\t\t\t\terror_occurred: true,\n\t\t\t\terror_type: \"INVALID_DATE_LOGIC\",\n\t\t\t\terror_message: \"Check-out date must be after check-in date\",\n\t\t\t\textracted_data: bookingData,\n\t\t\t\toriginal_email: $('Get many messages (1)').item.json,\n\t\t\t\ttimestamp: new Date().toISOString()\n\t\t\t}\n\t\t};\n\t}\n\t\n\tconsole.log(\"Validation successful!\");\n\treturn {\n\t\tjson: {\n\t\t\terror_occurred: false,\n\t\t\tvalidated_data: bookingData\n\t\t}\n\t};\n\t\n} catch (error) {\n\tconsole.log(\"JSON parse error:\", error.message);\n\treturn {\n\t\tjson: {\n\t\t\terror_occurred: true,\n\t\t\terror_type: \"JSON_PARSE_ERROR\",\n\t\t\terror_message: error.message,\n\t\t\traw_output: $json.output,\n\t\t\toriginal_email: $('Get many messages (1)').item.json,\n\t\t\ttimestamp: new Date().toISOString()\n\t\t}\n\t};\n}"
},
"typeVersion": 2
},
{
"id": "6af4f7e8-e23b-4ce5-9f08-5545f192af4e",
"name": "提取附件数据",
"type": "n8n-nodes-base.extractFromFile",
"position": [
-1920,
976
],
"parameters": {
"options": {},
"operation": "pdf",
"binaryPropertyName": "={{ Object.keys($json.binary || {})[0] || 'attachment_0' }}"
},
"typeVersion": 1
},
{
"id": "0c7b7738-c233-4c71-b02c-f8b0331aa0f0",
"name": "检查附件",
"type": "n8n-nodes-base.if",
"position": [
-1040,
464
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "loose"
},
"combinator": "and",
"conditions": [
{
"id": "check-attachment",
"operator": {
"type": "number",
"operation": "gt"
},
"leftValue": "={{ Object.keys($binary || {}).length }}",
"rightValue": 0
}
]
},
"looseTypeValidation": true
},
"typeVersion": 2.2
},
{
"id": "61ea223c-c6b9-4e0f-a30c-d9bb33620a79",
"name": "配置:用户设置",
"type": "n8n-nodes-base.set",
"position": [
-1264,
464
],
"parameters": {
"values": {
"string": [
{
"name": "gSheetID",
"value": "1qhUoE4baN5TyO51mD2caYU789XizhXl3UDCCT0v83So"
},
{
"name": "adminEmailForErrors",
"value": "admin@hotel.com"
}
]
},
"options": {}
},
"typeVersion": 1
},
{
"id": "8aa4991f-6300-418d-b442-3540b8b48308",
"name": "筛选预订电子邮件",
"type": "n8n-nodes-base.filter",
"position": [
-1504,
528
],
"parameters": {
"options": {},
"conditions": {
"options": {
"version": 2,
"leftValue": "",
"caseSensitive": true,
"typeValidation": "strict"
},
"combinator": "or",
"conditions": [
{
"id": "filter-booking-subject",
"operator": {
"type": "string",
"operation": "contains",
"caseSensitive": false
},
"leftValue": "={{ $json.subject }}",
"rightValue": "Booking Request"
},
{
"id": "107664b3-31f6-4df6-89ef-33fc5af78cce",
"operator": {
"type": "string",
"operation": "contains"
},
"leftValue": "={{ $json.subject }}",
"rightValue": "reservation"
},
{
"id": "4de37c49-313a-4477-80cd-9553fde62f53",
"operator": {
"name": "filter.operator.equals",
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.subject }}",
"rightValue": "room request"
},
{
"id": "839bc665-ad8b-469c-862c-d911418d66ae",
"operator": {
"name": "filter.operator.equals",
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.subject }}",
"rightValue": "accommondation"
},
{
"id": "ec0fc23d-1083-4dac-a9ea-4c2a6eedb740",
"operator": {
"name": "filter.operator.equals",
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.subject }}",
"rightValue": "check-in"
},
{
"id": "4e923cdb-6127-4068-80cf-6b5cd4ebc98c",
"operator": {
"name": "filter.operator.equals",
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.subject }}",
"rightValue": "boking"
},
{
"id": "f6b9bf16-ad15-4e02-a78e-7e0b6a3adaf0",
"operator": {
"name": "filter.operator.equals",
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.subject }}",
"rightValue": "reserv"
},
{
"id": "77152b7b-6e55-494f-9e12-3e99c77570a6",
"operator": {
"name": "filter.operator.equals",
"type": "string",
"operation": "equals"
},
"leftValue": "={{ $json.subject }}",
"rightValue": "booking"
}
]
}
},
"typeVersion": 2.2
},
{
"id": "22027bbe-8ecf-4632-a856-3a5b23b8476c",
"name": "获取多条消息 (1)",
"type": "n8n-nodes-base.gmail",
"position": [
-1712,
528
],
"webhookId": "2b7ef828-6a6d-4930-ab92-9670869a1f75",
"parameters": {
"limit": 1,
"simple": false,
"filters": {},
"options": {
"downloadAttachments": true
},
"operation": "getAll"
},
"typeVersion": 2.1
},
{
"id": "69b7cb59-f2d9-4f7e-badc-19ac6555437d",
"name": "查找传入电子邮件",
"type": "n8n-nodes-base.gmailTrigger",
"position": [
-1936,
528
],
"parameters": {
"filters": {
"labelIds": [
"INBOX"
]
},
"pollTimes": {
"item": [
{
"mode": "everyHour"
}
]
}
},
"typeVersion": 1.2
},
{
"id": "c1258b0a-561d-46f6-84f8-f5cc549382d5",
"name": "便签24",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1168,
752
],
"parameters": {
"color": 7,
"width": 432,
"height": 400,
"content": "## 验证数据并检查缺失值"
},
"typeVersion": 1
},
{
"id": "f469b629-e26a-44c9-aa2b-bc66f5bc2215",
"name": "便签21",
"type": "n8n-nodes-base.stickyNote",
"position": [
-592,
1184
],
"parameters": {
"color": 2,
"width": 640,
"height": 304,
"content": "## ⚠️ 错误处理流程"
},
"typeVersion": 1
},
{
"id": "e13d1fb4-9d47-4aeb-a4d4-7f7a0383b0a9",
"name": "便签20",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1968,
752
],
"parameters": {
"color": 4,
"width": 736,
"height": 736,
"content": "## 从 PDF 提取 *数据*"
},
"typeVersion": 1
},
{
"id": "ec304ef1-5e6b-409c-a07a-e83c81efd08d",
"name": "便签19",
"type": "n8n-nodes-base.stickyNote",
"position": [
-1968,
336
],
"parameters": {
"color": 5,
"width": 608,
"height": 352,
"content": "## 邮件提取"
},
"typeVersion": 1
},
{
"id": "56eb53d5-2cc4-4bc7-8706-c7645a167dce",
"name": "便签18",
"type": "n8n-nodes-base.stickyNote",
"position": [
-592,
576
],
"parameters": {
"color": 3,
"width": 1056,
"height": 432,
"content": "## 记录到 *案例* 和 *团队分配* 表格"
},
"typeVersion": 1
},
{
"id": "8becac6c-0937-4c0c-b0b2-9f7c72267818",
"name": "便签17",
"type": "n8n-nodes-base.stickyNote",
"position": [
480,
592
],
"parameters": {
"color": 6,
"width": 352,
"height": 248,
"content": "## 📊 成功指标记录器"
},
"typeVersion": 1
},
{
"id": "6c05a64f-0a42-4731-9c60-477695a52dbc",
"name": "便签2",
"type": "n8n-nodes-base.stickyNote",
"position": [
-2560,
320
],
"parameters": {
"width": 496,
"height": 1168,
"content": "# 🏨 使用 AI 将 Gmail 中的酒店预订请求自动化到 Google Sheets"
},
"typeVersion": 1
}
],
"pinData": {},
"connections": {
"Check for Errors": {
"main": [
[
{
"node": "Apply Business Rules",
"type": "main",
"index": 0
}
],
[
{
"node": "Log Error to Sheet",
"type": "main",
"index": 0
}
]
]
},
"Log Error to Sheet": {
"main": [
[
{
"node": "Send Error Notification",
"type": "main",
"index": 0
}
]
]
},
"Validate Extraction": {
"main": [
[
{
"node": "Check for Errors",
"type": "main",
"index": 0
}
]
]
},
"Apply Business Rules": {
"main": [
[
{
"node": "Log Team Assignment",
"type": "main",
"index": 0
},
{
"node": "Append to Cases Sheet",
"type": "main",
"index": 0
}
]
]
},
"Check for Attachment": {
"main": [
[
{
"node": "Extract Attachment Data",
"type": "main",
"index": 0
}
],
[
{
"node": "OpenAI Model for Email Text",
"type": "main",
"index": 0
}
]
]
},
"OpenAI Model for PDF": {
"main": [
[
{
"node": "Validate Extraction",
"type": "main",
"index": 0
}
]
]
},
"Append to Cases Sheet": {
"main": [
[
{
"node": "Send Confirmation Email",
"type": "main",
"index": 0
}
]
]
},
"Filter Booking Emails": {
"main": [
[
{
"node": "Configuration: User Settings",
"type": "main",
"index": 0
}
]
]
},
"Get many messages (1)": {
"main": [
[
{
"node": "Filter Booking Emails",
"type": "main",
"index": 0
}
]
]
},
"Extract Attachment Data": {
"main": [
[
{
"node": "OpenAI Model for PDF",
"type": "main",
"index": 0
}
]
]
},
"Send Confirmation Email": {
"main": [
[
{
"node": "Log Success Metrics",
"type": "main",
"index": 0
}
]
]
},
"Look for incoming emails": {
"main": [
[
{
"node": "Get many messages (1)",
"type": "main",
"index": 0
}
]
]
},
"OpenAI GPT Model (Email)": {
"ai_languageModel": [
[
{
"node": "OpenAI Model for Email Text",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"OpenAI Model for Email Text": {
"main": [
[
{
"node": "Validate Extraction",
"type": "main",
"index": 0
}
]
]
},
"Configuration: User Settings": {
"main": [
[
{
"node": "Check for Attachment",
"type": "main",
"index": 0
}
]
]
},
"OpenAI GPT Model (Attachment)": {
"ai_languageModel": [
[
{
"node": "OpenAI Model for PDF",
"type": "ai_languageModel",
"index": 0
}
]
]
}
}
}常见问题
如何使用这个工作流?
复制上方的 JSON 配置代码,在您的 n8n 实例中创建新工作流并选择「从 JSON 导入」,粘贴配置后根据需要修改凭证设置即可。
这个工作流适合什么场景?
高级 - 文档提取, AI 摘要总结
需要付费吗?
本工作流完全免费,您可以直接导入使用。但请注意,工作流中使用的第三方服务(如 OpenAI API)可能需要您自行付费。
相关工作流推荐
初学者数据分析:使用 GPT-4o 在 Google Sheets 中合并、筛选和汇总
初学者数据分析:使用 GPT-4o 在 Google Sheets 中合并、筛选和汇总
If
Set
Code
+9
21 节点Robert Breen
文档提取
在可视化参考库中探索n8n节点
在可视化参考库中探索n8n节点
If
Ftp
Set
+93
113 节点I versus AI
其他
电子邮件扫描和Google表格采购订单创建
使用Gemini AI从Gmail提取采购订单并保存至Google表格
If
Set
Code
+8
15 节点Sayone Technologies
文档提取
使用OpenAI GPT处理和总结来自电子邮件和消息应用的PDF文件
使用OpenAI GPT处理和总结来自电子邮件和消息应用的PDF文件
If
Set
Code
+10
28 节点papcy
文档提取
API速率限制与认证FAQ测试
使用GPT-4o-mini、Google表格和Slack提醒自动化API常见问题质量测试
If
Set
Code
+7
19 节点Rahul Joshi
文档提取
自动化学术论文元数据及变量提取,从Gemini到Google Sheets
自动化学术论文元数据及变量提取,从Gemini到Google Sheets
Set
Code
Wait
+14
39 节点OwenLee
文档提取