Guide

Extract Attachment Data With an AI Agent

An AI agent reads attachments off its own inbox, extracts structured fields from every PDF or invoice with a model, and routes the clean data downstream.

Written by Pouya Sanooei Software Engineer

VerifiedCLI 3.1.20 · Nylas managed · last tested June 14, 2026

How does an AI agent extract structured data from email attachments?

An attachment-extraction agent runs a four-stage pipeline: it lists inbound messages that carry files, downloads each attachment to disk, passes the file to a model that returns a fixed set of fields, and routes that structured output to a database or another service.

The agent reads from its own inbox, so a vendor emailing an invoice to invoices@yourapp.nylas.email triggers the whole flow without a human opening the mail.

Attachment extraction pipeline: list messages with attachments, download the file, extract structured fields with a model, then route the clean JSON downstreamSearch--has-attachmentDownloadattachments downloadExtractmodel → JSONRoutestore / forward

The value is turning an unstructured PDF into a typed record. A purchase order keyed by hand takes a few minutes per document; the same fields come back from a model in under 2 seconds. Because the agent owns the inbox, every attachment it sees is one it was sent on purpose — there are no unrelated personal documents in the way.

How do you pull attachments off the agent's inbox?

Two commands get the file. The nylas email search command with --has-attachment returns only messages that carry files, and nylas email attachments download writes the binary to disk. The download command takes the attachment id, then the message id, then an output path. For the full mechanics of listing and saving files across providers, see the attachment reference guide linked below.

# Find unread messages that carry attachments
nylas email search "*" --has-attachment --unread --json

# List the attachments on one message, then download by id
nylas email attachments list msg_abc123 --json
nylas email attachments download att_x1y2z3 msg_abc123 --output ./inbox/

Each downloaded file lands in ./inbox/ ready for the extraction step. A typical 200 KB PDF downloads in well under a second, so a batch of 50 attachments is on disk in seconds rather than the minutes a manual save-each loop costs.

How does the model turn a file into structured fields?

The extraction step hands the downloaded file to your agent's model with a fixed output schema — a JSON Schema contract — and the model returns those fields as JSON. You define the shape once, the fields you actually need downstream, and the model fills them for every document.

The same pattern handles receipts, signed forms, shipping manifests, or resumes; only the schema changes. A constrained schema is what makes the output safe to store. The shipping manifest below is one illustrative field set. For a complete, invoice-specific build — accounting routing, duplicate detection, and an approval loop — see the invoice-intake agent guide linked at the end. This guide stays general, so you swap these fields for whatever the document carries.

Define the target fields, pass the file plus the schema to the model, and validate the JSON it returns. The block below is the extracted output for one shipping manifest — the same six typed fields come back for every document of that type. Keeping the set to 6 fields keeps extraction accurate and the prompt cheap.

{
  "carrier": "Acme Freight",
  "tracking_number": "AF-20418",
  "ship_date": "2026-06-10",
  "delivery_eta": "2026-06-14",
  "item_count": 14,
  "destination": "Austin, TX"
}

Validate the result before trusting it. If the model returns an item_count that isn't a number or a date that doesn't parse, route that document to a human queue instead of the database. Roughly 1 in 20 real-world scans needs that fallback — a skipped check is how bad data reaches your records.

How do you route the extracted data?

Once the JSON validates, the agent routes it: write the record to your database, post it to an internal API, or reply to the sender to confirm receipt. The reply closes the loop so the sender knows the document landed. The agent sends that confirmation from its own address, which keeps the whole exchange on one auditable identity.

The nylas email send command delivers the confirmation in 1 CLI invocation — the agent reads the structured JSON result back in a single round trip. A single command replaces an SMTP relay, and the message threads from the same inbox that received the attachment, so the full intake-to-confirm trail lives in one place.

# Confirm receipt from the agent's own address
nylas email send \
  --to supplier@example.com \
  --subject "Manifest AF-20418 received" \
  --body "Logged 14 items, ETA 2026-06-14."

How do you keep attachment extraction safe?

An email attachment is untrusted content: a PDF can carry text that tries to steer the model, the prompt-injection risk (OWASP LLM01) that ranks #1 in the OWASP LLM Top 10 (2025). Run the pipeline on an agent account so the model that reads the document has no access to private mail, and cap what the agent can send with outbound rules.

Containment lives outside the agent's decision loop. This is the lethal trifecta in miniature — private data, untrusted content, and external communication. Extraction removes one leg by starting from an inbox with zero private threads, so a prompt-injection payload buried in an attachment has nothing to exfiltrate and no thread to reach. Treat extracted text as data, never as a command, and the document can't prompt its way past a rule.

Next steps