{
  "id": "Ou60pWZbLHTpoeH8",
  "meta": {
    "builderVariant": "mcp",
    "aiBuilderAssisted": true
  },
  "name": "Build a trip itinerary from booking confirmation emails with Gemini and Sheets",
  "tags": [],
  "nodes": [
    {
      "id": "700202ec-3a45-477d-afaa-4414a5ed887c",
      "name": "Watch for Booking Emails",
      "type": "n8n-nodes-base.gmailTrigger",
      "position": [
        80,
        48
      ],
      "parameters": {
        "simple": false,
        "filters": {
          "q": "subject:(confirmation OR booking OR reservation OR itinerary)",
          "readStatus": "unread"
        },
        "options": {},
        "pollTimes": {
          "item": [
            {
              "mode": "everyHour"
            }
          ]
        }
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.4
    },
    {
      "id": "841e6ecc-8c72-44b9-982f-d892187892db",
      "name": "Extract Booking with Gemini",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "onError": "continueErrorOutput",
      "position": [
        608,
        48
      ],
      "parameters": {
        "text": "=You are a travel assistant. Read the email below and decide whether it is a genuine travel booking confirmation. Set is_booking to false for marketing emails, fare alerts, newsletters or cancellations. If it is a booking, set type to flight, hotel, car, train or activity, and extract the provider, the confirmation or booking reference, the start date and time, the end date where relevant, the location name and full address, the useful details such as flight number, seat, room type or pickup instructions, and the total cost. Use YYYY-MM-DD for dates and 24-hour HH:MM for times. Leave a field empty rather than guessing.\n\nFrom: {{ $json.from }}\nSubject: {{ $json.subject }}\n\nEmail:\n{{ $json.text }}",
        "batching": {},
        "promptType": "define",
        "hasOutputParser": true
      },
      "typeVersion": 1.9
    },
    {
      "id": "261fec13-33b3-4c15-b366-5ab5467179ac",
      "name": "Google Gemini Chat Model",
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "position": [
        576,
        208
      ],
      "parameters": {
        "options": {
          "temperature": 0.1
        },
        "modelName": "models/gemini-3.1-flash-lite"
      },
      "credentials": {
        "googlePalmApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.1
    },
    {
      "id": "cd57c4b7-43cc-4e7d-887e-b9d772ac5077",
      "name": "Booking Parser",
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "position": [
        800,
        208
      ],
      "parameters": {
        "jsonSchemaExample": "{\"is_booking\":true,\"type\":\"flight\",\"provider\":\"ANA\",\"confirmation_number\":\"ABC123\",\"start_date\":\"2026-08-01\",\"start_time\":\"10:00\",\"end_date\":\"2026-08-01\",\"location\":\"Haneda Airport Terminal 3\",\"address\":\"Tokyo, Japan\",\"details\":\"Flight NH6 to San Francisco, seat 32A\",\"total_cost\":\"98000\"}"
      },
      "typeVersion": 1.3
    },
    {
      "id": "a5fad42f-b592-4e70-a2ac-1ba663e4b2fb",
      "name": "Parse Booking Fields",
      "type": "n8n-nodes-base.code",
      "position": [
        1312,
        32
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "const src = $json.output || $json;\nconst mail = $('Watch for Booking Emails').item.json;\nconst conf = String(src.confirmation_number || '').trim();\nconst type = String(src.type || 'other').toLowerCase();\nreturn {\n  isBooking: src.is_booking === true && conf.length > 0,\n  type: type,\n  provider: src.provider || '',\n  confirmationNumber: conf || ('NO-REF-' + mail.id),\n  startDate: src.start_date || '',\n  startTime: src.start_time || '',\n  endDate: src.end_date || '',\n  location: src.location || '',\n  address: src.address || '',\n  details: src.details || '',\n  totalCost: src.total_cost || '',\n  messageId: mail.id,\n  subject: mail.subject || ''\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "1383e338-a88f-407b-8346-f50ca6dc9883",
      "name": "Is a Real Booking",
      "type": "n8n-nodes-base.if",
      "position": [
        1504,
        32
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 1,
            "leftValue": "",
            "caseSensitive": false,
            "typeValidation": "loose"
          },
          "combinator": "and",
          "conditions": [
            {
              "operator": {
                "type": "boolean",
                "operation": "true",
                "singleValue": true
              },
              "leftValue": "={{ $json.isBooking }}"
            }
          ]
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "720af09e-9b9d-421a-88a6-a2bd8668f283",
      "name": "Save Booking to Itinerary",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        1808,
        16
      ],
      "parameters": {
        "operation": "appendOrUpdate",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "Itinerary"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "",
          "cachedResultName": "Select your spreadsheet"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "1f63e3d2-1b24-49d0-94ec-8704fa0d002b",
      "name": "Mark Booking as Processed",
      "type": "n8n-nodes-base.gmail",
      "position": [
        2048,
        16
      ],
      "parameters": {
        "messageId": "={{ $(\"Parse Booking Fields\").item.json.messageId }}",
        "operation": "markAsRead"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "69647a67-c1b4-4e42-8207-5b3359cf6dcd",
      "name": "Route by Booking Type",
      "type": "n8n-nodes-base.switch",
      "position": [
        2320,
        0
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "conditions": {
                "options": {
                  "version": 1,
                  "leftValue": "",
                  "caseSensitive": false,
                  "typeValidation": "loose"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $(\"Parse Booking Fields\").item.json.type }}",
                    "rightValue": "flight"
                  }
                ]
              }
            },
            {
              "conditions": {
                "options": {
                  "version": 1,
                  "leftValue": "",
                  "caseSensitive": false,
                  "typeValidation": "loose"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $(\"Parse Booking Fields\").item.json.type }}",
                    "rightValue": "hotel"
                  }
                ]
              }
            }
          ]
        },
        "options": {
          "fallbackOutput": "extra",
          "renameFallbackOutput": "Other"
        }
      },
      "typeVersion": 3.2
    },
    {
      "id": "24047b02-13fb-41b0-b1ff-4db70e1980de",
      "name": "Email Flight Added",
      "type": "n8n-nodes-base.gmail",
      "position": [
        2560,
        -16
      ],
      "parameters": {
        "sendTo": "={{ $('Set Your Email').item.json.notifyEmail }}",
        "message": "={{ \"Added to your trip:\\n\\n\" + $(\"Parse Booking Fields\").item.json.provider + \" \" + $(\"Parse Booking Fields\").item.json.details + \"\\nDeparts: \" + $(\"Parse Booking Fields\").item.json.startDate + \" at \" + $(\"Parse Booking Fields\").item.json.startTime + \"\\nFrom: \" + $(\"Parse Booking Fields\").item.json.location + \"\\nConfirmation: \" + $(\"Parse Booking Fields\").item.json.confirmationNumber + \"\\n\\nCheck in online 24 hours before departure.\" }}",
        "options": {},
        "subject": "={{ \"Flight added to your itinerary - \" + $(\"Parse Booking Fields\").item.json.startDate }}",
        "emailType": "text"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "0e39fa2b-4256-4f84-bc95-d825b0a02599",
      "name": "Email Hotel Added",
      "type": "n8n-nodes-base.gmail",
      "position": [
        2560,
        144
      ],
      "parameters": {
        "sendTo": "={{ $('Set Your Email').item.json.notifyEmail }}",
        "message": "={{ \"Added to your trip:\\n\\n\" + $(\"Parse Booking Fields\").item.json.provider + \"\\nCheck in: \" + $(\"Parse Booking Fields\").item.json.startDate + \"\\nCheck out: \" + $(\"Parse Booking Fields\").item.json.endDate + \"\\nAddress: \" + $(\"Parse Booking Fields\").item.json.address + \"\\nConfirmation: \" + $(\"Parse Booking Fields\").item.json.confirmationNumber + \"\\n\\n\" + $(\"Parse Booking Fields\").item.json.details }}",
        "options": {},
        "subject": "={{ \"Stay added to your itinerary - \" + $(\"Parse Booking Fields\").item.json.startDate }}",
        "emailType": "text"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "8f6246a0-7d9d-4027-a8db-17d40e29a252",
      "name": "Email Booking Added",
      "type": "n8n-nodes-base.gmail",
      "position": [
        2560,
        304
      ],
      "parameters": {
        "sendTo": "={{ $('Set Your Email').item.json.notifyEmail }}",
        "message": "={{ \"Added to your trip:\\n\\nType: \" + $(\"Parse Booking Fields\").item.json.type + \"\\nProvider: \" + $(\"Parse Booking Fields\").item.json.provider + \"\\nStarts: \" + $(\"Parse Booking Fields\").item.json.startDate + \" \" + $(\"Parse Booking Fields\").item.json.startTime + \"\\nLocation: \" + $(\"Parse Booking Fields\").item.json.location + \"\\nConfirmation: \" + $(\"Parse Booking Fields\").item.json.confirmationNumber + \"\\n\\n\" + $(\"Parse Booking Fields\").item.json.details }}",
        "options": {},
        "subject": "={{ \"Booking added to your itinerary - \" + $(\"Parse Booking Fields\").item.json.startDate }}",
        "emailType": "text"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "2eeb04b9-a424-462a-bac9-6fd385d924d1",
      "name": "Mark Non-Booking as Read",
      "type": "n8n-nodes-base.gmail",
      "position": [
        1808,
        208
      ],
      "parameters": {
        "messageId": "={{ $(\"Parse Booking Fields\").item.json.messageId }}",
        "operation": "markAsRead"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "a73a5fd6-31b4-4f70-b384-0463d1840f95",
      "name": "Mark Unparsed as Read",
      "type": "n8n-nodes-base.gmail",
      "position": [
        1056,
        176
      ],
      "parameters": {
        "messageId": "={{ $(\"Watch for Booking Emails\").item.json.id }}",
        "operation": "markAsRead"
      },
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "7a960cc6-653a-4041-9aa7-0be13fd6b095",
      "name": "Overview Sticky",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -656,
        -288
      ],
      "parameters": {
        "width": 632,
        "height": 660,
        "content": "## Build a trip itinerary from booking confirmation emails with Gemini and Sheets\n\n### How it works\nTravel bookings arrive as a dozen unreadable confirmation emails from different airlines, hotels and rental companies, and you end up screenshotting them all. This template watches Gmail for booking confirmations and sends each one to a Basic LLM Chain with Google Gemini, which first decides whether it is a genuine booking - filtering out fare alerts, newsletters and marketing - then extracts the type, provider, confirmation number, dates and times, location, full address, details and cost. Each booking is upserted into a Google Sheets itinerary keyed by confirmation number, so airlines re-sending the same email never create duplicates, and every processed message is marked as read. A Switch then sends a confirmation email tailored to flights, hotels or anything else.\n\n### Setup\n1. Connect Gmail, Google Gemini (PaLM) API and Google Sheets.\n2. Point the Sheets node at your spreadsheet (tab: Itinerary).\n3. Adjust the Gmail search query if your providers use different subject wording.\n\n### Customization tips\nAdd a Google Calendar node to create events, or a daily digest of the next day."
      },
      "typeVersion": 1
    },
    {
      "id": "c804a963-f339-4aa8-b528-6a48f89391af",
      "name": "S1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        0,
        -288
      ],
      "parameters": {
        "color": 7,
        "width": 500,
        "height": 756,
        "content": "## 1. Watch the inbox & configure\nPoll Gmail for unread emails whose subject looks like a confirmation, booking, reservation or itinerary, then set the address your itinerary updates should go to."
      },
      "typeVersion": 1
    },
    {
      "id": "bc936343-5ee7-4c8a-860e-51bd1df7e4f8",
      "name": "S2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        528,
        -288
      ],
      "parameters": {
        "color": 7,
        "width": 692,
        "height": 756,
        "content": "## 2. AI extraction (Basic LLM Chain)\nGemini decides whether it is a real booking and pulls out the reference, dates, times, address and cost. Failures are marked read so they never loop."
      },
      "typeVersion": 1
    },
    {
      "id": "094e6007-31ef-4810-8fad-fbe4f72e2432",
      "name": "S3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1248,
        -288
      ],
      "parameters": {
        "color": 7,
        "width": 940,
        "height": 756,
        "content": "## 3. Filter, de-duplicate & store\nMarketing emails are marked read and dropped. Real bookings are upserted by confirmation number, so resent emails update the row instead of duplicating it."
      },
      "typeVersion": 1
    },
    {
      "id": "9d664368-0c79-438e-9f4d-d202adb6ff05",
      "name": "S4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2208,
        -288
      ],
      "parameters": {
        "color": 7,
        "width": 568,
        "height": 756,
        "content": "## 4. Confirm by type\nFlights get a departure and check-in reminder, hotels get check-in, check-out and the address, everything else gets a generic confirmation."
      },
      "typeVersion": 1
    },
    {
      "id": "e2bdcac7-d619-4aa7-9c5d-52c9a7b25107",
      "name": "Set Your Email",
      "type": "n8n-nodes-base.set",
      "position": [
        304,
        48
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "notify",
              "name": "notifyEmail",
              "type": "string",
              "value": "you@example.com"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    }
  ],
  "active": false,
  "settings": {
    "binaryMode": "separate",
    "availableInMCP": true,
    "executionOrder": "v1"
  },
  "versionId": "77c46207-cdc6-40de-a9b9-9f5beed311b3",
  "nodeGroups": [],
  "connections": {
    "Booking Parser": {
      "ai_outputParser": [
        [
          {
            "node": "Extract Booking with Gemini",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "Set Your Email": {
      "main": [
        [
          {
            "node": "Extract Booking with Gemini",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Is a Real Booking": {
      "main": [
        [
          {
            "node": "Save Booking to Itinerary",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Mark Non-Booking as Read",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Booking Fields": {
      "main": [
        [
          {
            "node": "Is a Real Booking",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Route by Booking Type": {
      "main": [
        [
          {
            "node": "Email Flight Added",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Email Hotel Added",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Email Booking Added",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Gemini Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "Extract Booking with Gemini",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Watch for Booking Emails": {
      "main": [
        [
          {
            "node": "Set Your Email",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Mark Booking as Processed": {
      "main": [
        [
          {
            "node": "Route by Booking Type",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Save Booking to Itinerary": {
      "main": [
        [
          {
            "node": "Mark Booking as Processed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Booking with Gemini": {
      "main": [
        [
          {
            "node": "Parse Booking Fields",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Mark Unparsed as Read",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}