{"slug": "working-with-attachments-in-agent-mail", "title": "Working With Attachments in Agent Mail", "summary": "Nylas has detailed how its Agent Accounts handle email attachments, including policy limits that control inbound files by size, count, and MIME type. The system drops over-limit attachments but still delivers the message, allowing agents to respond gracefully. Developers can set per-workspace policies to enforce different limits for different agents.", "body_md": "An invoice-processing agent receives an email at 2 a.m. The PDF it needs is attached — along with a 60 MB screen recording the sender included \"for context.\" Whether your agent handles that gracefully or chokes on it depends entirely on decisions you made weeks earlier: what your mailbox accepts, what it drops, and how your code pulls files out.\n\nHere's the full attachment path for a [Nylas Agent Account](https://developer.nylas.com/docs/v3/agent-accounts/) — the hosted, API-controlled mailboxes currently in beta — covering inbound downloads, outbound sends, and the policy limits that act as your first line of defense.\n\nWhen mail arrives, attachment IDs ride along on the message object. The download itself is one GET, streaming the raw bytes:\n\n```\ncurl --request GET \\\n  --url \"https://api.us.nylas.com/v3/grants/<GRANT_ID>/attachments/<ATTACHMENT_ID>/download?message_id=<MESSAGE_ID>\" \\\n  --header \"Authorization: Bearer <NYLAS_API_KEY>\"\n```\n\nNote the `message_id`\n\nquery parameter — attachments are addressed in the context of the message that carried them. If you want metadata before committing to the download (filename, content type, size), hit `GET /v3/grants/{grant_id}/attachments/{attachment_id}`\n\nfirst. For an agent deciding whether a file is worth processing, checking the content type before streaming megabytes is the obvious move.\n\nThe typical agent flow chains three calls: `message.created`\n\nwebhook fires → fetch the full message to get attachment IDs → download the ones that match what you're looking for.\n\nThis is the part most attachment guides skip. Before your webhook ever fires, the grant's [policy](https://developer.nylas.com/docs/v3/agent-accounts/policies-rules-lists/) decides which attachments survive. Three limits control inbound files:\n\n`limit_attachment_size_limit`\n\n— max size per attachment, in bytes`limit_attachment_count_limit`\n\n— max number of attachments per message`limit_attachment_allowed_types`\n\n— an allowlist of MIME typesA policy for that invoice agent might cap attachments at 25 MB (`26214400`\n\nbytes) and 20 files per message:\n\n```\ncurl --request POST \\\n  --url \"https://api.us.nylas.com/v3/policies\" \\\n  --header \"Authorization: Bearer <NYLAS_API_KEY>\" \\\n  --header \"Content-Type: application/json\" \\\n  --data '{\n    \"name\": \"Invoice agent policy\",\n    \"limits\": {\n      \"limit_attachment_size_limit\": 26214400,\n      \"limit_attachment_count_limit\": 20\n    }\n  }'\n```\n\nPolicies apply through workspaces: attach the `policy_id`\n\nto a workspace and every Agent Account in it inherits the limits. Every limit is optional — omit one and it defaults to your plan's maximum. Two scoping details save you confusion later:\n\n`PATCH`\n\non the grant:\n\n```\ncurl --request PATCH \\\n  --url \"https://api.us.nylas.com/v3/grants/<GRANT_ID>\" \\\n  --header \"Authorization: Bearer <NYLAS_API_KEY>\" \\\n  --header \"Content-Type: application/json\" \\\n  --data '{ \"workspace_id\": \"<WORKSPACE_ID>\" }'\n```\n\nThat's how you give the invoice agent strict attachment limits while a different workspace runs a support agent with looser ones — separate workspaces, separate policies, same application. One more guard: if you request a limit above your plan's maximum, the API rejects the policy with an error rather than silently clamping it.\n\nThe enforcement behavior is worth internalizing, because it's gentler than you might expect: **over-limit attachments are dropped from the stored message, but the message itself still arrives and message.created still fires.** Your agent gets the email text minus the oversized file. That 60 MB screen recording disappears; the invoice PDF under the cap comes through. No bounce, no silent message loss — just the offending payload stripped.\n\nFor an autonomous reader, that's exactly the failure mode you want. The model still sees the sender's words and can reply \"your attachment was too large, please resend under 25 MB\" instead of the conversation dead-ending.\n\nOne asymmetry to remember: these limits apply to **inbound mail only**. They're never applied to the stored sent copy, so anything your agent sends keeps all of its attachments in the sent folder regardless of what the policy says about incoming files.\n\nSending uses the same endpoint as any other message — `POST /v3/grants/{grant_id}/messages/send`\n\n— as a JSON body, or multipart when attachments are involved. The hard ceiling is 40 MB total outbound message size, enforced on every send path per the [mailbox documentation](https://developer.nylas.com/docs/v3/agent-accounts/mailboxes/).\n\nThat 40 MB is your limit, not the recipient's. Remote mail servers commonly enforce lower caps (around 25 MB is typical), so a message that clears your side can still bounce at the destination. If your agent regularly ships large files, sending a link instead of an attachment is the deliverability-friendly answer — and it sidesteps the size lottery entirely.\n\nWhen a send does fail, the deliverability webhooks (`message.send_failed`\n\n, `message.bounce_detected`\n\n) tell you, so the agent can fall back rather than assume delivery.\n\n**How do I find the messages that actually have attachments?** The messages list endpoint takes a `has_attachment`\n\nfilter, so a batch agent can query `GET /messages?has_attachment=true&in=inbox`\n\ninstead of fetching everything and checking each object. Combine it with `received_after`\n\nfor incremental sweeps.\n\n**Did a rule eat my attachment, or did the policy?** Rules don't strip attachments — they match sender fields and either block the whole message or route it. Attachment dropping is purely the policy's limits. If a whole message never arrived, check `GET /v3/grants/{grant_id}/rule-evaluations`\n\nto see whether an inbound `block`\n\nrule rejected it at SMTP; if the message arrived minus a file, that's the policy.\n\n**Do attachment limits affect what my agent sends?** No. Policy attachment limits are inbound-only and are never applied to the stored sent copy. Outbound, the only attachment-relevant constraint is the 40 MB total message size.\n\nA sane attachment setup for a production agent looks like:\n\n`message_id`\n\n,The interaction between these layers is the design insight: the policy handles the adversarial cases (junk payloads, malware-sized files, attachment bombs) before any code runs, so your application logic only ever sees attachments that are plausibly legitimate. Cheap defense, applied at the infrastructure level.\n\nSpin up a test mailbox with the [quickstart](https://developer.nylas.com/docs/v3/getting-started/agent-accounts/), email it a few files from your own account, and watch what the policy lets through. Then try emailing it something over your size limit — seeing the message arrive with the attachment stripped makes the whole model click.", "url": "https://wpnews.pro/news/working-with-attachments-in-agent-mail", "canonical_source": "https://dev.to/qasim157/working-with-attachments-in-agent-mail-d38", "published_at": "2026-06-16 17:05:54+00:00", "updated_at": "2026-06-16 17:17:43.483335+00:00", "lang": "en", "topics": ["developer-tools", "ai-agents", "ai-infrastructure"], "entities": ["Nylas", "Nylas Agent Account"], "alternates": {"html": "https://wpnews.pro/news/working-with-attachments-in-agent-mail", "markdown": "https://wpnews.pro/news/working-with-attachments-in-agent-mail.md", "text": "https://wpnews.pro/news/working-with-attachments-in-agent-mail.txt", "jsonld": "https://wpnews.pro/news/working-with-attachments-in-agent-mail.jsonld"}}