# Travel Itinerary Building from Emails

This pattern covers extracting flight/hotel/car rental data from IMAP emails and assembling a structured itinerary document.

## Typical sources

| Type | Senders | Data format |
|---|---|---|
| Flights | Copa Airlines, United, American, Delta, Allegiant | PDF attachment in multipart/mixed email |
| Hotel/Airbnb | Airbnb, Booking.com, VRBO | HTML email with dates, address, confirmation |
| Car rental | Avis, Hertz, Enterprise, Budget | HTML email with confirmation #, vehicle class |
| Account numbers | Avis account statements | HTML email with Wizard/Preferred number |

## Extraction flow

1. **Search inbox** — broad OR search across senders and subject keywords
2. **Filter** — skip survey/feedback/survey emails (Allegiant sends many post-flight surveys)
3. **Extract PDFs** — for airline tickets, extract the PDF attachment from multipart/mixed (see `references/pdf-attachment-extraction.md`)
4. **Parse with pdfminer** — extract flight numbers, times, dates, passenger names
5. **Build structured data** — leg-by-leg table with date, time, airport codes, flight numbers
6. **Search for ancillary bookings** — rental car, hotel, insurance in the same inbox

## Email search strategies for trip data

**Multiple sender search (one call per sender):**
```python
for sender in ["Copa", "Avis", "Allegiant", "Airbnb"]:
    status, data = conn.search(None, f'FROM "{sender}" SUBJECT "itinerary"')
```

**Keyword OR across subject lines:**
```python
status, data = conn.search(None, 'OR OR SUBJECT "Cartagena" SUBJECT "flight" SUBJECT "itinerary"')
```

**Chain multiple filters:**
```python
status, data = conn.search(None, 'FROM "Copa" OR SUBJECT "Cartagena" BODY "Cartagena"')
```

## Account number extraction (Avis Wizard #, etc.)

Account numbers are often embedded in HTML email statements rather than PDFs. The Wizard number may be partially redacted in the HTML (`P72***`). If the user has past rentals, the confirmation email will show the full account number in the header or body.

**Method:** Search the raw HTML for the account section:
```python
idx = html.find('Wizard')
if idx >= 0:
    # Extract text between Wizard #: and next HTML tag
    m = re.search(r'Wizard\s*#[:\\s]*<span[^>]*>(.*?)</span>', html[idx:idx+300], re.DOTALL)
```

For Avis Wizard numbers specifically: the HTML statement email shows the number partially redacted (e.g. `P72***`). The full number appears on the Avis website after login. If the user needs to book, they'll need to get it from their Avis account or a past confirmation email.

## Itinerary document structure

Use a consistent markdown template:

```markdown
# [Destination] Trip — [Date Range]

**Travelers:** [Names with ages if relevant]

---

## Flight Schedule

### [Traveler Names] — [Airline] (Confirmation: [CODE])

| Date | Leg | Flight | Departs | Arrives | Duration |
|---|---|---|---|---|---|

---

## Departure Day — [Date]

### Time-based Agenda

| Time | Activity | Notes |
|---|---|---|

---

## Activities

- Attractions categorized as Must-See, Kid-Friendly, Adult, Rainy Day
- Estimated time per attraction
- Location relative to accommodation

---

## Checklist

- [ ] Items specific to this trip
```

## Travel plan adjustments

When the user provides corrections to the itinerary (all on same flight, TSA PreCheck, no checked bags, gate arrival 90 min before boarding), apply them in order:

1. **Same flight for all** — update the flight schedule table to list all travelers under one confirmation
2. **TSA PreCheck** — adjust MCO arrival: PreCheck average wait ~10-15 min vs 30-45 min standard. Can shift airport arrival 30 min later.
3. **No checked bags** — remove bag claim step from timeline. Carry-ons go straight to security after shuttle.
4. **Gate 90min before departure** — work backward from boarding time (~30 min before departure). Add 30 min buffer for food/restroom. This sets the "at security" time, then subtract PreCheck estimate to set "arrive airport" time.
5. **No rental car in destination** — note as "taxis/ride-share from airport" in the itinerary. Research Avis options as reference data only, document clearly that no booking is needed.
6. **Car rental: monitor inbox for confirmations** — the user may start the Avis rental process themselves (email verification code login). Search inbox for "Avis" since last 24 hours for confirmation emails. Avis sends multiple emails per booking (security code, then reset password, then confirmation). The confirmation email contains the reservation number, vehicle class, pick-up/drop-off locations and times, and estimated total. Extract and add to the itinerary.

## Real-time inbox monitoring during trip planning

When the user says "check email now for [rental/flight/hotel]" during active trip planning:

1. Search inbox for the relevant sender since last 24h: `conn.search(None, f'(FROM "Avis" SINCE {since})')`
2. Multiple emails from the same sender in the same session likely form a chain: security code → password reset → confirmation
3. The confirmation email is the most important — extract reservation number, dates, vehicle class, and any cost
4. Report findings concisely in a table
5. Update the itinerary checklist to mark the booking as completed
6. Remove the associated todo item from the trip planning checklist

## Drive time estimation

For Savannah → MCO (July 11, Saturday, ~285 miles):

| Condition | Time | Notes |
|---|---|---|
| No traffic | 4h 15m | Typical late-night / early morning |
| Light traffic | 4h 30m | Leave before 9 AM Saturday |
| Moderate | 5h | Jacksonvlille I-95 afternoon backup |
| Heavy | 5h 30m | Holiday weekend, accident, or rain |

- Saturday I-95 southbound through Jacksonville typically backs up around lunchtime (11 AM - 1 PM)
- Best departure: 8:30 AM from Savannah → arrives MCO ~1:30 PM with buffer
- Worst case: leave later than 9 AM, hit Jacksonville lunch rush, arrive MCO 2:30+ PM

## Pitfalls

- **Allegiant sends survey/feedback emails** for 48+ hours after each flight. Exclude these by filtering out subject lines containing "feedback" or "survey".
- **Allegiant flight confirmation details are in HTML tables** — the FROM/TO airport codes appear inline (e.g. "SAV to CAK") rather than in structured fields. Parse these with regex.
- **Copa confirmation emails are in two parts** — 1) a "Your reservation is processing" email, then 2) the "Electronic ticket receipt and confirmation" with the actual PDF. The processing email has the confirmation code but no flight details.
- **Copa flights depart from MCO, not SAV** — Copa flies out of Orlando (MCO) for Cartagena. The user drives from Savannah to MCO. If searching for the user's flight and finding Copa, check the departure airport — it may not be their home city.
- **Carrier gateways are unreliable for SMS delivery** — AT&T's `@txt.att.net` gateway was shut down. Don't use carrier gateways for automated messages unless confirmed working.
- **Anita and Germaine were booked on Copa together** — same confirmation code (A4GSFD) produces two separate PDFs, one per passenger. Download both: the text extraction gives the same data repeated with different names.
- **Avis Wizard number is partially redacted** in account statement emails. The last 3 characters show as `***`. For booking purposes, the user must retrieve the full number from their Avis account profile page.
- **One-way rental from Savannah to MCO**: Avis allows one-way rentals. Pick up at Savannah location, drop at MCO airport. Need full Wizard # for Preferred Plus benefits.
- **Copa flight PDFs contain 6-7 inline image attachments** alongside the ticket PDF. The PDF is the last or second-to-last MIME part in multipart/mixed.
- **Global Entry on return: MCO is first port of entry.** Though final destination is Savannah, US customs is cleared at Orlando. Account for ~10-15 min GE kiosk time in the return timeline.
- **Avis sends multiple emails per booking in a chain**: security code → (optional) password reset → confirmation. The confirmation email arrives last and contains the reservation number, vehicle class, and pricing. Search `FROM "Avis"` since the last 24h to find all of them.
- **Avis confirmation has a "Ford Explorer or Similar"** as default for mid-size SUV. The reservation number format is `#XXXXXXXXUSX` (9 digits + US + 1 digit).
- **Avis one-way rental allowed**: pick up at Avis Savannah (SAV), drop at MCO. No extra fee.
- **Avis verification code emails** have subject "Avis: Your security code." The code appears in the email body. The agent can read it from the inbox before the user finds it.
- **Avis confirmation email arrives last** in a chain: security code → (optional) password reset → confirmation. Search FROM "Avis" since last 24h to get all of them.
