# Authenticate an AI agent to email

Source: https://developer.nylas.com/docs/cookbook/agents/authenticate-ai-agent-email/

An AI agent that reads, drafts, or sends email needs a way into a real mailbox, and the way you grant that access decides almost everything about the system's security. Get it wrong and the agent holds raw provider tokens, sees more than it should, or sends from an address that confuses the people it's writing to. Get it right and the agent acts inside a clear, revocable boundary you can audit later.

This guide covers the two authentication patterns for connecting an AI app to email: delegated access to a user's existing mailbox through an OAuth grant, and giving the agent its own dedicated account. It shows how each one works through the API, and is direct about the security tradeoffs so you can pick the pattern that fits your product.

## What is the best way to authenticate an AI app with a user email account?

The safest way to authenticate an AI app with a user's email account is delegated OAuth: the user signs in to their own provider, approves a scoped set of permissions, and your app receives a grant that represents that authorized connection. The agent never sees the user's password and never holds the raw Google or Microsoft refresh token directly.

Delegated access means the user stays in control. They consent through their provider's own login screen, and they can revoke that consent at any time from their account settings. Your agent works through `GET /v3/grants/{grant_id}/messages` and similar grant-scoped routes, so every call is bound to one specific authorized mailbox. The grant model covers Google, Microsoft, Yahoo, iCloud, IMAP, and Exchange behind one schema, which means a single integration reaches 6 providers. Token storage, refresh, and rotation happen behind the API instead of in your agent's process, removing the single most common source of leaked credentials in email integrations.

## What role does OAuth play when connecting AI agents to user email accounts?

OAuth is the consent and authorization layer between your AI agent and the user's mailbox. It lets the user grant your app a limited, revocable token without ever sharing their password, and it scopes exactly what the agent can do: read only, read and send, or full mailbox access. The resulting grant is the agent's credential for every later request.

Three OAuth facts shape an agent build. First, scopes are the agent's blast radius. A triage agent that only reads should request read scopes, not send scopes, so a prompt-injection attack can't make it email anyone. Second, basic authentication is gone on the major providers: Microsoft deprecated it for all Exchange Online accounts on October 1, 2022, so OAuth is the only supported path for Microsoft 365. Third, tokens expire. Refresh tokens keep the grant alive without re-prompting the user, and the API refreshes them for you so the agent doesn't break mid-task. The [Nylas authentication overview](/docs/v3/auth/) explains hosted OAuth, scopes, and the grant lifecycle in full.

### Start the OAuth flow

The hosted OAuth flow begins at `GET /v3/connect/auth`. You redirect the user there with your `client_id`, a `redirect_uri`, and `provider`, and the API sends them to their provider's login screen. After they approve, the provider returns an authorization code to your callback. This one request replaces every provider-specific OAuth setup, across all 6 supported providers.

```bash
curl --request GET \
  --url 'https://api.us.nylas.com/v3/connect/auth?client_id=<NYLAS_CLIENT_ID>&redirect_uri=https%3A%2F%2Fyourapp.com%2Fcallback&response_type=code&provider=google&login_hint=user@example.com'
```

### Exchange the code for a grant

Once the user lands back on your `redirect_uri` with a `code`, exchange it at `POST /v3/connect/token` with `grant_type` set to `authorization_code`. The response returns a `grant_id`, which is the durable handle your agent uses for every email call afterward. Each `code` is one-time-use, so if the exchange fails you restart the flow rather than retrying the same code.

```bash
curl --request POST \
  --url 'https://api.us.nylas.com/v3/connect/token' \
  --header 'Content-Type: application/json' \
  --data '{
    "code": "<AUTH_CODE>",
    "client_id": "<NYLAS_CLIENT_ID>",
    "client_secret": "<NYLAS_API_KEY>",
    "redirect_uri": "https://yourapp.com/callback",
    "grant_type": "authorization_code"
  }'
```


> **Info:** 
> **New to Nylas?** Start with the [quickstart guide](/docs/v3/getting-started/) to set up your app and connect a test account before continuing here.


## How do I give an AI agent its own email address?

To give an AI agent its own email address, you provision a dedicated mailbox for the agent and connect it through the same OAuth grant flow a human account uses. The agent then owns a real, addressable inbox: people can email it, it can reply under its own identity, and its activity stays separate from any human's personal mail.

A dedicated account suits agents that act as a participant, not an assistant. A scheduling bot, a support triage address, or an autonomous worker that receives and answers mail on its own behalf all read cleaner when they send from `agent@yourcompany.com` rather than borrowing a person's mailbox. You connect that account with the identical `/v3/connect/auth` flow shown above, store its `grant_id`, and the agent sends through `POST /v3/grants/{grant_id}/messages/send` exactly like any other grant. The tradeoff is real: a standalone account means you own provisioning, lifecycle, and offboarding for an identity no human watches, so set up [recipient restrictions](/docs/cookbook/agents/restrict-agent-recipients/) and logging before it sends a single message. Nylas Agent Accounts package this dedicated-mailbox pattern so you skip the manual provider setup.

### Send from the agent's grant

After the agent owns a grant, sending is one call to `POST /v3/grants/{grant_id}/messages/send`. The request body takes `to`, `subject`, and `body`, and the API delivers through the connected provider so messages land in real inboxes with correct authentication. Once a message payload passes 3 MB you switch to the `multipart/form-data` schema, which providers cap at 25 MB for the full request.

```bash
curl --request POST \
  --url 'https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/messages/send' \
  --header 'Authorization: Bearer <NYLAS_API_KEY>' \
  --header 'Content-Type: application/json' \
  --data '{
    "to": [{ "email": "customer@example.com" }],
    "subject": "Your request is confirmed",
    "body": "Hi, your booking for Thursday at 2pm is confirmed."
  }'
```

## Delegated grant vs dedicated agent account

Both patterns authenticate through OAuth and end with a `grant_id`, so the question isn't which is more secure in the abstract: it's which identity the agent should act as. Delegated access has the agent work inside a human's mailbox with that person's consent. A dedicated account gives the agent a mailbox of its own. The table compares them on the decisions that matter when you wire up an AI email agent.

| Concern | Delegated user grant | **Dedicated agent account** |
| --- | --- | --- |
| **Whose mailbox** | An existing user's inbox | A mailbox the agent owns |
| **Consent** | User approves through their provider | You provision and connect it once |
| **Best for** | Assistants acting for a person | Bots that send and receive on their own |
| **Revocation** | User revokes anytime in provider settings | You disable the grant or account |
| **Send identity** | The user's address | The agent's own address |
| **Setup cost** | One OAuth flow per user | Provisioning plus lifecycle ownership |

The honest tradeoff: if your agent assists one person with their own mail, a delegated grant is simpler and safer because the human stays the owner and can pull access in two clicks. Reach for a dedicated account only when the agent genuinely needs a separate identity that outlives any single user session, and accept that you now own that mailbox's full lifecycle.

## Scope the grant to what the agent actually needs

Whatever pattern you choose, scope the grant tightly. An AI agent is an untrusted executor: a crafted message in the inbox can try to steer it, so the permissions the grant carries are your hard ceiling on what any injection can achieve. A read-only triage agent should never hold send scopes, and a drafting agent should write drafts rather than send directly.

This matters more for agents than for traditional apps because the instructions an agent follows partly come from the email it reads. Request the narrowest scope set that lets the task succeed, keep a human approval step in front of irreversible actions like sending, and log every call the agent makes against its `grant_id` so you have an audit trail. For the defensive layer around the agent's behavior, see [prevent prompt injection in email agents](/docs/cookbook/agents/prevent-prompt-injection/). Treat every grant as revocable and assume you'll need to cut one off fast someday.

## What's next

- [Act on behalf of a user](/docs/cookbook/use-cases/build/act-on-behalf-of-user/) for the delegated-access pattern in depth
- [Connect an LLM to an inbox](/docs/cookbook/ai/connect-llm-to-inbox/) to feed mailbox data into your model safely
- [Handle replies in agent accounts](/docs/cookbook/agent-accounts/handle-replies/) for two-way conversations from a dedicated mailbox
- [Nylas authentication overview](/docs/v3/auth/) for hosted OAuth, scopes, and the grant lifecycle