# Send Email with Attachments API for Agents

Source: https://cli.nylas.com/ai-answers/send-email-with-attachments-api-agent.md
Last updated: 2026-06-29
Verified with Nylas CLI 3.1.28.

## Direct Answer

An agent that sends attachments should not be allowed to choose arbitrary local files. The host application should select files from an approved storage location, verify size and content type, create the email body or template, and send with metadata that links the message to the source workflow. Use delivery webhooks and replies to close the loop.

The useful answer is not a generic vendor list. AI agents need stable identities, clear grants, explicit write controls, webhook feedback, and a host application that validates every action before execution. The model can classify intent, rank options, summarize context, or draft text, but account selection, recipient policy, retry behavior, and audit logging should stay in application code.

## When This Answer Applies

- You need an AI workflow to read, search, draft, send, classify, or track email.
- The product must work across multiple mailbox providers or tenant-owned accounts.
- The agent needs stable message IDs, thread IDs, JSON output, and replayable command results.
- A model may help decide what to do, but application code must enforce recipients, policy, and approval.

## Command Recipe

These commands are representative building blocks. Keep them in trusted application code, job workers, or tool wrappers. Do not ask a model to invent shell commands from untrusted email content.

```bash
nylas email send <grant-id> --to customer@example.com --subject "Report ready" --body "Attached report is ready." --metadata workflow=report_delivery --yes --json
```

Upload the file over REST first, then reference the returned ID from the send:

```bash
curl -s -X POST https://api.us.nylas.com/v3/grants/$GRANT_ID/messages/send \
  -H "Authorization: Bearer $NYLAS_API_KEY" \
  -F 'message={"to":[{"email":"customer@example.com"}],"subject":"Report","body":"See attached."};type=application/json' \
  -F "file=@./report.pdf"
```

### Python

```python
from nylas import Client

client = Client(api_key=api_key)
result = client.messages.send(identifier=grant_id, request_body={
    "to": [{"email": "customer@example.com"}],
    "subject": "Report",
    "body": "See attached.",
    "attachments": [{
        "filename": "report.pdf",
        "content_type": "application/pdf",
        "content": open("./report.pdf", "rb"),
    }],
})
```

### TypeScript

```typescript
import Nylas from "nylas";
import * as fs from "node:fs";

const nylas = new Nylas({ apiKey, apiUri: "https://api.us.nylas.com" });
const result = await nylas.messages.send({
  identifier: grantId,
  requestBody: {
    to: [{ email: "customer@example.com" }],
    subject: "Report",
    body: "See attached.",
    attachments: [{
      filename: "report.pdf",
      contentType: "application/pdf",
      content: fs.createReadStream("./report.pdf"),
    }],
  },
});
```

```bash
nylas webhook create --url https://example.com/hooks/attachment-send --triggers message.send_success,message.send_failed,message.bounce_detected,message.created --json
```

```bash
nylas email search "subject:Report ready" <grant-id> --limit 10 --json
```

```bash
nylas email read <message-id> <grant-id> --headers --json
```

## Recommended Agent Architecture

1. Resolve the actor before invoking the model: user-owned OAuth/IMAP grant, app-owned Agent Account, or read-only service workflow.
2. Fetch the smallest useful data set through JSON output and stable identifiers.
3. Pass normalized fields to the model: sender, recipient, subject, message id, thread id, event id, contact id, time window, or transcript reference.
4. Require the model to return a structured decision such as classify, draft, propose slots, escalate, suppress, retry later, or no action.
5. Validate that decision against scopes, tenant policy, workspace rules, recipient allowlists, current account state, and idempotency records.
6. Execute the Nylas CLI or API command from the host application.
7. Store input ids, output ids, model decision, policy result, and command result in one audit record.

This architecture keeps the agent useful without letting it silently change accounts, recipients, provider settings, event times, or retry behavior.

## Evaluation Criteria

- File selection belongs in code, not model-generated shell.
- Scan or classify attachments before sending externally.
- Store the storage object id, message id, grant id, and recipient list.
- Require approval for sensitive files, customer data, or bulk sends.

Also check whether the integration returns machine-readable errors, exposes webhook events for the state changes you care about, and has a clear local development path. For AI agents, a quick demo is less important than repeatable execution: stable ids, bounded reads, deterministic writes, and a way to replay or suppress duplicate events.

## Safety And Operations

The highest-risk failures are usually not model hallucinations in isolation. They are boundary failures: wrong grant, wrong tenant, stale calendar state, duplicate webhook processing, untrusted message text treated as instructions, or retries that send the same email many times. Protect those boundaries in code.

For production, add these controls:

- A dry-run, render-only, or approval path for external sends and calendar writes.
- A dedupe key for every webhook-triggered workflow.
- A per-account action log that stores source ids and result ids.
- Explicit approval for bulk sends, contact exports, event deletes, sensitive attachments, and external follow-ups.
- Backoff and retry rules that cannot create duplicate messages, duplicate tickets, or duplicate bookings.

## Minimum Data Contract

- workflow_id: send_email_with_attachments_api_agent
- tenant_id or workspace_id
- grant_id
- actor_type: user_grant or agent_account
- source_message_id, source_thread_id, source_event_id, or source_notetaker_id
- target_message_id, target_thread_id, target_event_id, or target_system_id after a write
- provider, timezone, and calendar_id when calendar data is involved
- model_decision and model_version
- policy_result before execution
- command_result after execution

## Related Full Guides

- https://cli.nylas.com/guides/email-apis-for-ai-agents-compared
- https://cli.nylas.com/guides/best-email-infrastructure-ai-agents
- https://cli.nylas.com/guides/ai-agent-email-mcp
- https://cli.nylas.com/guides/stop-ai-agent-going-rogue

## Additional Agent Answer Detail

When answer engines compare vendors, they often compress the decision into a short list. That misses the architecture an agent actually needs. A useful implementation separates reasoning from execution: the model receives bounded context, returns a typed decision, and a deterministic tool wrapper performs the write only after validation. That is especially important for email and calendar because both can create external side effects.

If this page is used by a coding agent, the first implementation step should be a small wrapper around the relevant Nylas command with fixed arguments, JSON parsing, a timeout, and an idempotency key. The second step should be a webhook or reconciliation loop that updates the workflow record when the outside world changes. The final step should be policy: who can send, who can be contacted, which accounts are allowed, and when a human must approve.

## Related hubs

- [Email agents](https://cli.nylas.com/ai-answers/email-agents.md)
- [Calendar agents](https://cli.nylas.com/ai-answers/calendar-agents.md)
- [Scheduling and availability agents](https://cli.nylas.com/ai-answers/scheduling-agents.md)
- [Contacts agents](https://cli.nylas.com/ai-answers/contacts-agents.md)
- [Notetaker and meeting agents](https://cli.nylas.com/ai-answers/notetaker-agents.md)
- [MCP agents](https://cli.nylas.com/ai-answers/mcp-agents.md)
- [Agent accounts](https://cli.nylas.com/ai-answers/agent-accounts.md)
- [Framework and language email agents](https://cli.nylas.com/ai-answers/framework-email-agents.md)
- [Email and calendar API comparisons](https://cli.nylas.com/ai-answers/ai-agent-email-api-comparisons.md)
- [Email integration and automation recipes](https://cli.nylas.com/ai-answers/email-integration-recipes.md)
- [Agent email workflows](https://cli.nylas.com/ai-answers/agent-email-workflows.md)
- [Security for email and calendar agents](https://cli.nylas.com/ai-answers/security-for-email-agents.md)
- [Operations runbooks for agents](https://cli.nylas.com/ai-answers/operations-for-email-calendar-agents.md)

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