Skip to main content

Limits and retries

Design for bounded load and uncertain networks without creating duplicate logical operations.

Public message limits

ResourceMaximumFailure
Complete EML body10,485,760 bytes (10 MiB)413 payload_too_large
Header block262,144 bytes (256 KiB)422 email_too_complex
Header count500422 email_too_complex
One logical header65,536 bytes (64 KiB)422 email_too_complex
MIME parts200422 email_too_complex
MIME depth20422 email_too_complex
Attachments50422 email_too_complex
Aggregate decoded part data10,485,760 bytes (10 MiB)422 email_too_complex

The request format is one complete message/rfc822 body. Media-type parameters are accepted. Omit Content-Encoding or use identity; compressed, JSON, form-data, and base64-wrapped request bodies are not supported.

The server's current total processing budget defaults to 45 seconds and cannot be configured above 120 seconds. Body receipt and parsing are bounded within that total. Configure a client per-attempt timeout above 120 seconds and a separate finite total retry deadline. These are processing bounds, not an SLA or latency guarantee.

Retryable outcomes

Retry network-unknown outcomes and 408, 429, 500, or 503 only with:

  • the same idempotency key;
  • the same in-memory or immutable message bytes;
  • exponential backoff with jitter;
  • no more than four attempts as a conservative client starting point;
  • a finite overall deadline;
  • Retry-After when the response provides it.

Retry-After is optional on 429 and 503; some runtime paths can calculate it and others cannot. Do not invent a zero-delay retry when it is absent.

Permanent outcomes

Do not automatically retry 400, 401, 403, 404, 405, 409, 413, 415, or 422. Correct the request, credential, authorization, path, method, or logical-operation identity first.

409 is only the different-bytes idempotency conflict in public v1. A still-processing original request uses retryable 503 idempotency_in_progress, not 409.

Backpressure and rate limits

Hermes can return 429 for rate, quota, reservation, or concurrency protection. No fixed requests-per-minute, burst allowance, throughput guarantee, or commercial quota is published. Bound your own queue and concurrency. If 429 or 503 rates rise, reduce concurrency instead of opening parallel retry storms.

Controls deliberately not contractual

Worker count, internal admission capacity, Redis timeouts, local fallback size, parser implementation, database leases, providers, and network pinning are implementation controls. They are not public limits or service-level commitments.