Source: https://cli.nylas.com/guides/agent-attachment-data-extraction

# 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](https://cli.nylas.com/authors/pouya-sanooei) Software Engineer

Updated June 14, 2026

> **TL;DR:** An agent finds attachments with `nylas email search "*" --has-attachment --json`, pulls each file with `nylas email attachments download`, hands the file to a model that returns a fixed JSON shape, and routes the result. Run it on an agent account so the agent never touches a person's inbox.

## 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.

```bash
# 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](https://json-schema.org/) 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.

```json
{
  "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.

```bash
# 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)](https://genai.owasp.org/llmrisk/llm01-prompt-injection/) 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](https://simonwillison.net/2025/Jun/16/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

- [Parse Email Attachments](https://cli.nylas.com/guides/parse-email-attachments) — the full list-and-download reference across every provider
- [Create an AI Agent Email Identity](https://cli.nylas.com/guides/create-ai-agent-email-identity) — provision the inbox this pipeline reads from
- [Build an Invoice-Intake Agent](https://cli.nylas.com/guides/invoice-intake-agent-account) — the invoice-specific application of this pattern, with accounting routing and approvals
- [Build an AI Email Triage Agent](https://cli.nylas.com/guides/build-ai-email-triage-agent) — classify and route messages before extraction runs
- [Extract Meetings and Contacts From Email](https://cli.nylas.com/guides/extract-contacts-appointments-ai) — the same extract-validate-write pattern applied to message bodies
- [Build a KYC Document-Collection Agent](https://cli.nylas.com/guides/kyc-document-collection-agent) — attachment extraction applied to identity-document intake and chasing
- [Stop Your AI Agent From Going Rogue](https://cli.nylas.com/guides/stop-ai-agent-going-rogue) — the full lethal-trifecta containment model for agents that read untrusted files
- [Full command reference](https://cli.nylas.com/docs/commands) — every `nylas email` subcommand and flag

## Try Nylas CLI

Install the CLI with `curl -fsSL https://cli.nylas.com/install.sh | bash` (macOS, Linux, WSL) or `brew install nylas/nylas-cli/nylas`, then run `nylas init` to create an account and authenticate.

**Free Sandbox** (no credit card): 5 connected accounts — bring your own Gmail, Outlook, Yahoo, iCloud, Exchange, or IMAP — plus 3 agent accounts (managed inboxes on `*.nylas.email`). Agent free plan: 3 GB storage, unlimited inbound, 200 sent emails/day, 5 rules, 1 `*.nylas.email` subdomain, and unlimited custom domains. Production is uncapped and requires a credit card: https://www.nylas.com/pricing/
