55 lines
2.4 KiB
Markdown
55 lines
2.4 KiB
Markdown
# 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.
|