# Email API errors

The stable error codes the email API returns for Gmail and Outlook mailboxes, with the extra fields every email error carries and what to do about each code.

Email errors use the standard [error envelope](/guides/error-handling) plus five fields. Branch on `code`, never on the HTTP status: the same problem can surface at different stages with different statuses.

## First call

Send from an address the Outlook mailbox has no rights on:

```bash
curl -X POST "https://zernio.com/api/v1/email/messages" \
  -H "Authorization: Bearer $ZERNIO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "accountId": "ACCOUNT_ID", "from": "ceo@acme.com", "to": [{ "email": "ada@example.com" }], "subject": "Hi", "text": "Hello" }'
```

Exchange refuses it, and the API answers `403`:

```json
{
  "error": "This mailbox has no Send As or Send on Behalf right on the from address.",
  "type": "invalid_request_error",
  "code": "from_not_allowed",
  "param": "from",
  "provider": "microsoft",
  "providerError": { "message": "The user account which was used to submit this request does not have the right to send mail on behalf of the specified sending account." },
  "retryable": false,
  "requestId": "6f1c2a9e-4d0b-4b7e-9a51-0c3f2d8e7b14",
  "docsUrl": "https://docs.zernio.com/guides/email-errors#from_not_allowed"
}
```

| Field | What it holds |
|-------|---------------|
| `provider` | `google` or `microsoft`, when the mail provider refused the request |
| `providerError` | The provider's own `code` and `message`, for logs and support |
| `retryable` | Whether the same request can succeed later. Retry sends with the same `Idempotency-Key` |
| `requestId` | Also in the `X-Request-Id` header. Quote it to support |
| `docsUrl` | The entry for the `code` on this page |

## Codes

### from_not_allowed

`400` or `403`. The mailbox may not send as `from`. Zernio answers `400` when the address is not in `GET /v1/email/send-as`; Exchange refuses at send time with `403`.

On Outlook, declare a shared mailbox with `POST /v1/email/send-as` first, and have an admin grant Send As.

### signature_unavailable

`400`. `appendSignature: true` but the sending address has neither a Zernio default signature nor a Gmail one. Create one with `POST /v1/email/signatures` and `defaultFor`, or pass `signatureId`.

### unsupported_for_provider

`400`. The feature does not exist for this mailbox provider. The message names the `capabilities` key; read `capabilities` on the account before calling.

### draft_conflict

`412`. The draft changed since the `If-Match` version, often because the user edited it in Gmail or Outlook. `details.draft` holds the draft as it is now. Review it, then retry with its `version`.

### draft_sending

`409`. A send of this draft is already in flight. Wait for it to finish; `retryable` is `true`.

### draft_not_found

`404`. The draft was deleted, trashed or sent from the mail client. Read the Sent folder before creating it again.

### attachment_too_large

`413`. The attachments of one mail pass the provider limit, forwarded ones included. `details.limitBytes` gives the limit, 25 MB.

### idempotency_key_reused

`422`. The `Idempotency-Key` was used before with a different body. Use a fresh key for a different mail.

### rate_limited

`429`. The provider throttled the mailbox, or it is in a sending cooldown. Wait for `Retry-After`.

### email_send_cap_reached

`429`. The mailbox reached its daily send cap. `details.cap.resetsAt` says when it resets.

### provider_unavailable

`502`. The mail provider timed out or failed on its side. Retry with the same `Idempotency-Key`; `retryable` is `true`.

### platform_api_error

`502`. The provider refused the request for a reason not listed above. `providerError` says why; `retryable` is `false`.

## Related

- [Error handling](/guides/error-handling)
- [Idempotency](/guides/idempotency)
- [Gmail email](/platforms/google/email) and [Outlook email](/platforms/microsoft/email)