Skip to content
Skip to main content

Idempotent send requests

Last updated:

Nylas’s send endpoints accept an Idempotency-Key header so you can safely retry a send without delivering the same message twice. This is the cornerstone for any send pipeline that retries automatically: workflow engines, background queues that redeliver on worker crash, or client code that retries after a network blip.

Both send endpoints accept the same Idempotency-Key header with the same semantics:

  • Grant-based send: POST /v3/grants/{grant_id}/messages/send (API reference)
  • Transactional send (Beta): POST /v3/domains/{domain_name}/messages/send (API reference)

Generate a unique key per logical send (a UUID v4 is a safe choice) and pass it in the Idempotency-Key header:

  • Max length: 256 characters.
  • Uniqueness: a key represents one logical send. Generate a fresh key for each new message.
  • Format: any string up to 256 characters.

When Nylas returns a cached response, the body and status code are identical to the original response, and the Idempotent-Response header is set to true. Check this header to tell whether the provider was actually contacted on this request:

HTTP/1.1 200 OK
Idempotent-Response: true
Content-Type: application/json
{ "data": { ... }, "request_id": "..." }

The first request through a key never has this header set; only retries that hit the cache do.

  • TTL: keys are valid for 1 hour after the first request. Once the TTL elapses, the key can be reused freely.
  • Grant-based send is scoped per grant. The same key under two different grants creates two independent cache entries.
  • Transactional send is scoped per Nylas application.
StatusError typeWhen it happens
400api.invalid_idempotency_keyThe Idempotency-Key header is longer than 256 characters.
409api.invalid_idempotent_requestA previous request used the same key with a different payload.
409api.concurrent_idempotent_requestA request with the same key is currently in flight.

Error response bodies follow the standard Nylas error shape (request_id, error.type, error.message). For the full error schema, see Sending errors.

Use this table to decide whether to reuse the original key or generate a new one:

ResponseRetry withNotes
Network failure (no response received)Same keyThe cornerstone use case. The first request may or may not have reached Nylas. Retrying with the same key is safe.
409 api.concurrent_idempotent_requestSame keyWait a few seconds and try again. Another caller is processing the same logical send.
429 rate limitDifferent keyNylas caches the 429 against the key, so a retry with the same key gets the cached 429 back and Nylas doesn’t attempt the send. If the response includes a Retry-After header, wait that many seconds. A replayed 429 counts down from the original wait rather than restarting it. Without the header, back off. Then retry with a new key. A 429 on a raw MIME send doesn’t guarantee the message wasn’t delivered, so check the mailbox’s Sent Items first.
4xx other than api.concurrent_idempotent_requestDifferent keyThe request was rejected (bad payload, auth failure, validation error). Fix the underlying issue, then retry with a fresh key.
5xx from Nylas (not a provider error)Usually same keyRetry behavior here isn’t as well-defined — it depends on the error and when it happened, so read the error message before deciding, the status code alone doesn’t tell you which case you’re in. Example: Nylas returns a 504 Gateway Timeout however the provider completed the send but was delayed. Keep retrying with the same key until the real send response is echoed back. While the original request is still in flight you may see 409 api.concurrent_idempotent_request; once it settles, the cached response (success or error) is returned. If instead the error indicates a connect-phase failure, Nylas never reached the destination mail server at all and nothing was sent, retry with a new key instead. See the worked example below.
5xx provider errorDifferent keyThe provider rejected the message. Address the cause, then retry with a fresh key. Reusing the original key would just return the same error.

Suppose an IMAP send times out because Nylas can’t reach the recipient’s mail server at all (for example, a firewall or DNS issue on their end). Nothing is accepted by the mail server, so there’s no send to protect with the same key:

  1. You send with Idempotency-Key: f47ac10b-58cc-4372-a567-0e02b2c3d479. Nylas attempts to connect to the mail server and gets no response.
  2. If you retry with the same key while that first attempt is still running, you get 409 api.concurrent_idempotent_request.
  3. Nylas eventually gives up and caches a 5xx against that key. Retrying with the same key just replays that same 5xx, since nothing was ever sent for it to resolve into.
  4. Generate a new key and retry. This reaches the mail server again, giving you a genuine second attempt instead of a repeated failure.

This is the opposite of the delayed-response case above, where the provider already sent the message and the same key eventually settles to a 200. Here, nothing reached the provider, so there’s no result to wait for.

  • Idempotency is enforced at the Nylas layer only. Nylas does not propagate the key to downstream providers (Google, Microsoft, Yahoo, IMAP, EWS).
  • TTL is fixed at 1 hour so you should implement retries within this time period.