Files
hermes-skills/skills/email/imap-email-search-and-extract/references/pdf-attachment-extraction.md
T

2.4 KiB

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.

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

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.