# PDF Attachment Extraction from Multipart/Mixed Emails

Airline ticket receipts (Copa, American, United, Delta) often embed PDF attachments inside `multipart/mixed` MIME messages alongside inline images (logos, QR codes).

## Key pattern

The PDF is typically the **last meaningful attachment** in the MIME tree, surrounded by 6-8 `image/jpeg` inline images. Don't assume the first `.pdf` match is the right one — iterate all parts and pick the one with the correct filename.

```python
for part in raw.walk():
    fn = part.get_filename()
    if fn and fn.endswith('.pdf'):
        payload = part.get_payload(decode=True)
        # Save to disk
        with open("/tmp/ticket.pdf", 'wb') as f:
            f.write(payload)
        # Or parse directly from memory
        from pdfminer.high_level import extract_text
        from io import BytesIO
        text = extract_text(BytesIO(payload))
```

## Parsing e-ticket PDFs with pdfminer

Install: `pip3 install pdfminer.six`

```python
from pdfminer.high_level import extract_text
from io import BytesIO

text = extract_text(BytesIO(pdf_bytes))

# Extract flight numbers (Copa uses CM###)
for line in text.split('\n'):
    if 'Flight Number' in line or 'CM ' in line:
        flights.append(line.strip())
```

## Common airline PDF fields

| Airline | Flight prefix | Confirmation length | PDF attachment name |
|---|---|---|---|
| Copa | CM | 6 alphanumeric (A4GSFD) | ETKT_*.pdf |
| American | AA | 6 alphanumeric | e-ticket-*.pdf |
| United | UA | 6 alphanumeric | itinerary-*.pdf |
| Delta | DL | 6 alphanumeric | eTicket*.pdf |

## Pitfalls

- **Copa tickets have 6-8 inline image parts** (logo, QR, barcode, social icons) before the PDF. The PDF is typically the second-to-last or last attachment.
- **`get_content_charset()` may return None** on PDFs — use `utf-8` or `iso-8859-1` fallback for the PDF parsing step (the PDF itself is binary, the charset applies to the text portion of the email, not the attachment).
- **Copa confirmation codes look like A4GSFD** — 6 chars, alphanumeric. Found in the email subject line and the PDF body. Also stored in the email's `X-Confirmation` header (if present).
- **Header-only fetch** (`BODY.PEEK[HEADER.FIELDS]`) won't show attachment filenames. You need to fetch the full message body to find PDFs.
- **Some airlines use `Content-Type: application/octet-stream`** instead of `application/pdf` for PDF attachments. Check `get_filename()` regardless of content type.
