> ## Documentation Index
> Fetch the complete documentation index at: https://developers.telnyx.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Rate Limits & Quotas

> Rate limits, sending quotas, and request size limits for the Telnyx Email API — batch sending, scheduled sending, and how to request increases.

<Callout type="info">
  Rate limits protect the platform and ensure fair resource allocation. This page covers request and sending limits enforced by the Email API, and how to request increases.
</Callout>

## Request and message size limits

Three different ceilings apply at three different layers. They are frequently confused — only the first two reject a message.

| Limit                                                           | Value  | Enforced by               | Failure                                                                                                  |
| --------------------------------------------------------------- | ------ | ------------------------- | -------------------------------------------------------------------------------------------------------- |
| Message body (`html_body` + `text_body`, decoded)               | 1 MB   | Email API                 | `422` with code `10015`, detail "body exceeds size limit (maximum 1 MB)"                                 |
| Total message (decoded body + decoded attachments)              | 25 MB  | Email API                 | `422` with code `10015`, detail "message exceeds size limit (maximum 25 MB)"                             |
| HTTP request body                                               | 150 MB | Phoenix request parser    | `413` with code `10015`                                                                                  |
| Idempotency-keyed replay capture                                | 8 MB   | Telnyx Edge (API gateway) | `413 Payload Too Large` — keyed request over 8 MB is rejected at Edge. Unkeyed requests bypass this cap. |
| Batch messages per request (`POST /email_messages/batch`)       | 50     | Email API                 | `400` with code `10015`                                                                                  |
| Batch validations per request (`POST /email_validations/batch`) | 1,000  | Email API                 | `400` with code `10015`                                                                                  |

<Callout type="warning">
  **8 MB is not the request body limit.** It is the Edge gateway's replay cap for idempotency-keyed requests. A keyed request over 8 MB is rejected at the Edge with `413 Payload Too Large` — it never reaches the Email API. Unkeyed requests bypass this cap entirely. The limits that actually reject a message are the **1 MB decoded body** and **25 MB total message**, enforced by the Email API, which return `422`.
</Callout>

Attachments are base64-encoded in the request, so a 25 MB message occupies roughly 33 MB on the wire. The Email API measures **decoded** bytes, so budget against the decoded size, not the encoded payload.

A batch send with more than 50 messages is rejected with `400`:

```json theme={null}
{
  "errors": [
    {
      "code": "10015",
      "title": "Bad Request",
      "detail": "messages must contain at most 50 items"
    }
  ]
}
```

## Request rate limits

API requests are rate-limited at the Telnyx API edge. Exact per-endpoint rates depend on your account tier and are not fixed platform-wide constants — if you need a specific sustained request rate, contact support to confirm or raise your account's limits.

When you exceed the limit, you'll receive `429 Too Many Requests`.

<Callout type="warning">
  **Do not assume a `Retry-After` header is present.** The Email API's own `429` responses — daily send limit and reputation suspension — do **not** set `Retry-After`. Honor the header when it is present (edge-level rate limiting may supply it) and fall back to exponential backoff with jitter when it is absent. Never block on parsing a header that may not be there.
</Callout>

### Not every 429 is a rate limit

Two very different conditions return `429`, and they need opposite handling. Branch on the **error code**, never on the status alone.

| Code                       | Condition                                                                                                                  | What to do                                                                                                                                                    |
| -------------------------- | -------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `10011`                    | The account's **daily send limit** was exceeded. The detail names the limit and states that it resets at **midnight UTC**. | Queue the work and resume after the daily reset. Exponential backoff over seconds or minutes will not help — the counter is daily.                            |
| `reputation_suspended`     | The sending domain's reputation band dropped to `poor`.                                                                    | **Stop and remediate.** Retrying never succeeds and continued attempts worsen the signal. Reduce bounce and complaint rates, then confirm the band recovered. |
| *(no email-specific code)* | Edge-level request rate limiting.                                                                                          | Back off exponentially with jitter and retry.                                                                                                                 |

Both `10011` and `reputation_suspended` are rejected **before message creation** — no message record, no billing, no MTA injection.

### Reputation-based suspension

Separate from request rate limiting, sending can be suspended when a domain's reputation band drops to `poor`. This returns `429` with code `reputation_suspended`:

```json theme={null}
{
  "errors": [
    {
      "code": "reputation_suspended",
      "title": "Sending Suspended",
      "detail": "Sender domain reputation is too low. Sending has been suspended. Please contact support to resolve deliverability issues."
    }
  ]
}
```

See [Deliverability and Domain Warm-up](/docs/messaging/email/deliverability) for reputation guidance and recovery steps.

### Daily send limit

When an account exceeds its daily send quota, the send is rejected with `429` and code `10011`:

```json theme={null}
{
  "errors": [
    {
      "code": "10011",
      "title": "Too Many Requests",
      "detail": "Daily send limit of 1000 recipients exceeded. The limit resets at midnight UTC."
    }
  ]
}
```

The quota is counted in **recipients**, not API requests — a single request to five addresses consumes five slots. Suppressed recipients are filtered out before the count, so they don't consume quota. Sandbox sends are exempt.

## Sending quotas

Sending quotas vary by account tier. Contact your account manager for your current quota.

<Callout type="tip">
  Sandbox mode (`sandbox_mode: true`) lets you test the full send flow — validation, event creation, webhook firing — without actually delivering the message. Sandbox sends do not consume daily quota and are not billed.
</Callout>

### Billing

Outbound messages are billed **per recipient accepted into the outbound MTA queue**. A message addressed to five recipients is therefore *up to* five billable sends — one for each recipient the MTA accepts.

Recipients that fail before reaching the queue are **not** billable:

* Suppressed recipients (filtered before the send).
* Gateway rejections — the MTA refused the recipient at injection.
* Sandbox sends — nothing is delivered.
* System failures and cancellations that occur while the recipient is still pre-queue.

So a five-recipient send where two addresses are suppressed and one is rejected at injection bills for two, not five. Recipient-level outcomes are visible in the `recipient_statuses` counts on the message resource and in [per-recipient webhooks](/docs/messaging/email/webhooks-events). See your rate card or contact your account manager for pricing details.

## High-volume sending patterns

### Batch sending

For high-volume sending, use the batch endpoint to reduce API calls:

```bash curl theme={null}
curl -X POST https://api.telnyx.com/v2/email_messages/batch \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Idempotency-Key: 20dbec69-bc70-4fed-aec7-2a70af3b9524" \
  -d '{
    "messages": [
      {
        "from": "notifications@example.com",
        "to": [{"email": "user1@example.com"}],
        "subject": "Welcome",
        "text_body": "Welcome to our service!"
      },
      {
        "from": "notifications@example.com",
        "to": [{"email": "user2@example.com"}],
        "subject": "Welcome",
        "text_body": "Welcome to our service!"
      }
    ]
  }'
```

* Up to **50 messages** per batch request.
* The `Idempotency-Key` header applies to the entire batch — reuse it only for exact retries of the same batch body.
* Partial success returns `207 Multi-Status` with per-message results. See [Error Codes](/docs/messaging/email/error-codes#batch-specific-errors).

### Scheduled sending

Spread load over time using `scheduled_at`:

```json theme={null}
{
  "from": "notifications@example.com",
  "to": ["user@example.com"],
  "subject": "Scheduled message",
  "text_body": "This was scheduled.",
  "scheduled_at": "2027-03-14T09:00:00Z"
}
```

The message is saved with `status: "scheduled"` and dispatched at the specified time.

<Callout type="warning">
  **`scheduled_at` must be a future ISO 8601 timestamp.** A value in the past, or one that fails to parse, is **silently ignored** — the message is sent immediately as a normal send, with no error and no `scheduled` status. There is no validation error to catch, so validate the timestamp client-side before submitting. The legacy field name `send_at` is still accepted as a fallback, but `scheduled_at` is the canonical name.
</Callout>

<Callout type="info">
  **Scheduled sends do not consume daily quota at request time.** Quota is reserved when the scheduled worker actually fires, not when you submit the request. This means a scheduled send can be accepted today and still be rejected at fire time if the daily limit is exhausted then — in which case the message is marked `failed` and a `daily_limit_exceeded` event is recorded rather than a `429` being returned to you. Poll for that event type via `GET /email_events` to detect it; it is **not** available as a webhook subscription. Sandbox sends are likewise exempt from request-time quota reservation.
</Callout>

## Requesting limit increases

To increase your sending quotas or request rates:

1. Contact your account manager or Telnyx support.
2. Provide your expected sending volume (messages/day, messages/second).
3. Have your domain(s) verified and warmed up (see [Deliverability](/docs/messaging/email/deliverability)).

Contact your account manager for current quotas, pricing, and increase timelines.
