# Email API Without OAuth: The API-Key Alternative

Published: August 21, 2026

Why OAuth breaks AI agent email: consent screens, refresh token expiry, app verification. How an API-key email API gets an agent sending in minutes.

If you want an email API without OAuth, you need a provider that authenticates with a bearer API key instead of a user-delegated token. That means no consent screen, no refresh token rotation, no app verification review, and no per-user token store. You create a mailbox, get a key, and send. Robotomail works this way: one `Authorization: Bearer rm_...` header for every mailbox your agent owns.

This post explains exactly where OAuth breaks down for autonomous agents, what the failure modes look like in production, and what the API-key model changes.

## Why agents hit the OAuth wall

OAuth 2.0 was designed for a specific situation: a human user grants a third-party app limited access to their account. Every part of the flow assumes that human is present and consenting.

Agents violate that assumption. An agent is not accessing a person's mailbox on their behalf. It needs its own mailbox, its own address, and its own identity. Bolting an agent onto a human's OAuth grant creates problems that never go away.

Here is the concrete list of things that bite.

### The consent screen needs a browser and a human

To get an access token for Gmail or Microsoft Graph, someone has to open a browser, sign in, and click Allow. That is fine once, on your laptop, during development. It is a problem when:

- You are spinning up a mailbox per customer, per project, or per agent run.
- Your agent runs in a container with no browser and no interactive session.
- You need to reprovision after a token gets revoked at 3am.

Service accounts with domain-wide delegation are the usual escape hatch on Google Workspace, but they require you to own and administer a Workspace domain, configure delegation in the admin console, and impersonate a real user account that has to exist and be licensed. You have traded a consent screen for an admin console and a per-seat bill.

### Refresh tokens expire in ways you cannot fully control

An access token lives for about an hour. Your refresh token is supposed to carry you past that. In practice refresh tokens die for reasons outside your code:

- The user changes their password.
- The user revokes app access from their account security page.
- The app is still in testing status, where Google expires refresh tokens after seven days.
- The token has been unused past the provider's inactivity window.
- Too many refresh tokens were issued for the same client and user pair, and the oldest ones get evicted.

Each of those returns `invalid_grant`, which is a single opaque error covering all of them. Your agent stops working and the only real recovery is to put a human back in front of a consent screen. That is not an automation you can hand to a customer.

### Verification review gates your scopes

Gmail read and send scopes are restricted. If your app is going to be used outside your own organization, you go through an OAuth app verification process, which for restricted scopes includes a security assessment. Until you pass, you live with the unverified app warning and a hard cap on how many users can grant consent. We have watched teams lose weeks here for what amounted to "our bot needs to reply to a thread."

### You now run a token database

OAuth pushes stateful secret management into your app. You store refresh tokens, encrypt them, rotate them, handle the race where two workers refresh the same token concurrently and one gets a rotated token invalidated out from under it, and you monitor for silent expiry. None of that work is about email. It is all overhead created by the auth model.

### Scopes do not map to what an agent needs

Gmail's send scope covers sending as that user. There is no scope for "this agent gets an inbox that is not a person's inbox." So you either give the agent broad access to a real human mailbox, which is bad security, or you create a dummy human account for the agent, which means a seat license and a manual onboarding step per agent. We wrote more about this mismatch in [why Gmail and Outlook don't work for AI agents](/blog/gmail-outlook-dont-work).

## What "email API without OAuth" actually means

There are two distinct things people mean, and it matters which one you need.

**Sending only.** Transactional providers like SendGrid, Mailgun, Postmark and Resend authenticate with API keys. No OAuth. If your agent only needs to emit messages, that is solved. But most of these are one-way: the message goes out and replies land nowhere your agent can read.

**Sending and receiving.** An agent that negotiates with a vendor, chases an invoice, or books an appointment must read the reply, match it to the thread, and continue. That needs a real mailbox with an inbound path, still authenticated with a key. This is the harder category, and it is the one we built for. There is a longer breakdown in [email APIs that support receiving](/blog/email-ap-is-that-support-receiving).

## API key vs OAuth for agent email

| Concern | OAuth (Gmail, Graph) | API key (Robotomail) |
|---|---|---|
| Initial setup | Register app, configure consent screen, browser flow per account | Create key, call API |
| Human in the loop | Required for every grant | None |
| Credential lifetime | Access token ~1 hour, refresh token revocable | Key valid until you rotate it |
| Provisioning a new mailbox | New account or delegated user | One POST |
| Review process | Verification, security assessment for restricted scopes | None |
| Failure mode | `invalid_grant`, needs re-consent | HTTP 401, rotate key |
| State you store | Encrypted refresh tokens per account | One key in your secret manager |

The tradeoff is real, so state it plainly: an API key is a long-lived bearer credential. It does not expire on its own and it does not scope down to a single user's data by design. You mitigate that with rotation, least-privilege keys, and server-side storage, never in client code. What you get back is an auth model that a headless process can actually operate.

## Getting an agent sending without OAuth

Three steps, no browser.

1. **Get an API key.** One key authenticates every request across all your mailboxes. Details in the [authentication docs](/docs/authentication).

2. **Create a mailbox.** Each agent gets its own address, not a share of a human's inbox.

```bash
curl -X POST https://api.robotomail.com/v1/mailboxes \
  -H "Authorization: Bearer rm_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"address": "shopping-agent"}'
```

Or from the CLI:

```bash
npx @robotomail/cli mailbox create shopping-agent
```

3. **Send.** Same key, no token refresh.

```bash
curl -X POST https://api.robotomail.com/v1/mailboxes/mbx_shopping/messages \
  -H "Authorization: Bearer rm_your_api_key" \
  -H "Content-Type: application/json" \
  -d '{"to": ["vendor@example.com"], "subject": "Order #A-4521 delivery update?", "bodyText": "Hi, checking on the status of order A-4521."}'
```

Receiving is a registered webhook. Inbound mail arrives as JSON your handler can parse directly:

```json
{
  "event": "message.received",
  "data": {
    "message_id": "...", "mailbox_id": "...", "mailbox_address": "shopping-agent@robotomail.co",
    "from": "vendor@example.com", "subject": "Re: Order #A-4521 delivery update?", "body_text": "...",
    "thread_id": "...", "received_at": "2026-04-17T10:00:00.000Z"
  }
}
```

To reply in the same thread, POST a message with `inReplyTo` set to the inbound `message_id`. No IMAP session, no history sync, no polling loop. The [receive and reply guide](/docs/guides/receive-and-reply) has the full flow.

## When OAuth is still the right answer

Be honest about this. Use OAuth when:

- The requirement is genuinely "read and act on **this specific human's** existing inbox," for example a triage assistant that summarizes a user's mail. That is delegated access and OAuth is the correct primitive.
- You need to send from an address on a domain you do not control, where the mailbox already lives in Google Workspace or Microsoft 365 and must stay there.
- Compliance requires that every action be traceable to a named user's grant.

Use API-key infrastructure when the agent needs its own identity. The dividing question is simple: is the mailbox the agent's, or is it a person's? If it belongs to the agent, OAuth is solving a problem you do not have. For a fuller side-by-side, see our [Gmail API comparison](/compare/gmail-api) and the roundup of [Gmail API alternatives for AI agents](/blog/gmail-api-alternatives-for-ai-agents).

## Keeping API keys safe

Dropping OAuth does not mean dropping discipline.

- **Server side only.** The key belongs in your backend or agent runtime, never in a browser bundle, mobile app, or prompt context the model can leak.
- **Rotate on a schedule and on suspicion.** Create the new key, deploy, then revoke the old one so there is no downtime window. See the [API keys reference](/docs/api/api-keys).
- **Separate keys per environment.** Staging and production should never share a credential, so revoking one never takes down the other.
- **Do not let the model see it.** If an LLM is orchestrating calls, the key lives in your tool implementation, not in the tool arguments or system prompt.
- **Watch for 401s in your logs.** A sudden cluster means a revoked or rotated key, which is a much easier diagnosis than untangling `invalid_grant`.

## FAQ

### Can I use SMTP instead of OAuth?

Yes, SMTP with a username and password avoids OAuth, but Google and Microsoft have both restricted basic authentication for their consumer and business mail platforms, so app passwords and legacy SMTP auth are increasingly unavailable or require exceptions. SMTP also gives you no inbound path, so you still need IMAP polling to read replies.

### Is an API key less secure than OAuth?

Different, not strictly worse. OAuth's short-lived access tokens limit the blast radius of a leak, which is a genuine advantage. An API key compensates with immediate revocation and simple rotation, and it removes an entire class of expiry failures. Store it server side, scope it per environment, and rotate it.

### Do I still need SPF, DKIM and DMARC?

If you send from your own domain, yes. Authentication of your app to the API is separate from authentication of your mail to receiving servers. On a platform domain we handle alignment for you. On a custom domain you publish the DNS records, described in the [custom domain guide](/docs/guides/custom-domain).

### How many mailboxes can one API key manage?

One key covers every mailbox on your account, so provisioning a mailbox per agent, per customer, or per workflow run is a single POST each. That is the main structural advantage over OAuth, where every new mailbox means a new grant or a new licensed user.

Ready to skip the consent screen? Create a mailbox and send your first message in a few minutes at [robotomail.com](https://robotomail.com).
