What does an email API idempotency key do?
Your send request times out. The email might already have been accepted, but your worker has no response. Starting another send with a fresh key treats that uncertainty as permission to send again.
An idempotency key identifies the intended operation across HTTP attempts. Keep these identities separate:
| Identity | What it represents | How to use it |
|---|---|---|
| Application operation ID | The business decision to send one email | Use it to find the durable send record |
| Idempotency key | The retry identity for that operation | Keep it unchanged across retries |
| HTTP attempt | One request over the network | Record each attempt without replacing the operation key |
| Send-attempt identifier | The send you can inspect through Mailera | Store it when available for status lookup |
For example, sending an approved support reply is one operation. Retrying its request after a connection failure is another HTTP attempt, not another decision to email the customer.
For HTTP background, see RFC 9110’s section on idempotent methods. Mailera’s integration point is the Idempotency-Key header on its send endpoint.
Keep outbound send deduplication separate from incoming-event deduplication. A repeated incoming event should resolve to the same application operation; otherwise, each handler can create a different send key before the outbound retry logic even runs.
How do you add Idempotency-Key to a Mailera send?
The Mailera developer overview introduces the API integration. For this workflow, the relevant request details are:
| Setting | Value |
|---|---|
| Base URL | https://mailera.app/api/public/v1 |
| Method and path | POST /mailboxes/{id}/send |
| Authentication | Authorization: Bearer $MAILERA_API_KEY |
| Retry identity | Idempotency-Key |
| Required scope | send |
| Idempotency window | 24 hours |
Follow this order:
- Open Settings → API key tab → Create key. Choose the required Mailbox scope and enable Send messages. Keep the credential in the
MAILERA_API_KEYenvironment variable, not in source code. - Assign an application operation ID to the approved email. This ID must remain stable if the job is delivered again.
- Assign one operation key. Persist it alongside the selected mailbox and the exact request payload before making the network request.
- Submit the saved payload to
/mailboxes/{id}/send, using the saved key as theIdempotency-Keyheader value. UseMAILBOX_IDfor the selected mailbox. - Save the response and any returned send-attempt identifier. If the response is lost, retain the operation record rather than replacing it.
Use the Mailera API documentation for the send body and response schema. Keep payload construction separate from retry handling: a retry should load the approved request, not rebuild it from current application data.

The API credential and the idempotency key serve different purposes. The credential authorizes access; the idempotency key identifies an operation. Never use the credential itself as the operation key, and redact authorization headers from logs.
How should keys survive retries and worker restarts?
Put the key in durable application storage, indexed by the business operation ID. Do not keep it only in a worker’s memory or generate it inside the HTTP retry loop. Persist one operation key with the approved request and reload both for retries. Keep credentials and personal information out of key values.
Your application operation ID is separate from the Mailera header value. A UUID can serve as that internal application ID: RFC 9562 defines UUIDs as 128-bit identifiers that require no central registration process.
A JavaScript persistence example
This Node.js example uses node:sqlite to save an existing operation key and its payload before any network request. The table and column names belong to your application, not to the Mailera API.
Prepare approved-send.json using the send schema in the API docs, and put the operation’s header value from your send integration in operation-key.txt. Give every intended email its own stable application operation ID; the fixed ID below represents one example operation.
import { readFileSync } from 'node:fs';
import { DatabaseSync } from 'node:sqlite';
const db = new DatabaseSync('send-operations.sqlite');
db.exec('CREATE TABLE IF NOT EXISTS sends (operation TEXT PRIMARY KEY, key TEXT NOT NULL, payload TEXT NOT NULL)');
const operation = 'approved-support-reply-1042';
db.exec('BEGIN IMMEDIATE');
let saved = db.prepare('SELECT key, payload FROM sends WHERE operation = ?').get(operation);
if (!saved) {
const payload = readFileSync('approved-send.json', 'utf8');
const key = readFileSync('operation-key.txt', 'utf8').trim();
db.prepare('INSERT INTO sends VALUES (?, ?, ?)').run(operation, key, payload);
saved = db.prepare('SELECT key, payload FROM sends WHERE operation = ?').get(operation);
}
db.exec('COMMIT');
db.close();On the next execution, the same operation ID loads the stored key and approved payload rather than creating replacements. Your retry path should use those persisted values. The snippet only handles persistence; it does not generate a header value or send email.
Keep the database file on persistent storage. For workers on separate machines, use a shared transactional store with a uniqueness constraint on the operation ID instead of giving each worker its own file. Otherwise, both workers can independently decide they are creating the first send.
In your production record, also retain the mailbox selection, attempt timestamps, and any returned send identifier. Prevent dispatch until the record is committed. If saving the record fails, stop before sending.

What should you do after a timeout or an expired window?
A timeout tells you that the client did not receive a complete result. Do not interpret it as proof that the send failed.
Mailera specifies a 24-hour idempotency window. Do not design a queue that depends on indefinite deduplication or assumes every retry renews that window.
| Situation | Next action | Avoid |
|---|---|---|
| Timeout within the window; original request is saved | If retrying, reuse the saved key, mailbox, and unchanged payload | Generating a replacement key |
| Send-attempt identifier is known | Inspect it with GET /sends/{id} | Creating another send just to obtain a clearer response |
| Outcome is uncertain and no identifier is available | Retain the original operation and reconcile the available request history | Marking it as unsent solely because of a timeout |
| Retry would be beyond the window | Stop automatic resend and reconcile before authorizing another send | Assuming the old key still prevents another send |
| Recipient or content needs to change | Treat the change as a separate approval decision and resolve the original operation first | Editing the payload under the original key |
GET /sends/{id} requires the send scope. Mailera lists queued, sending, sent, failed, and unknown as send-attempt statuses.
Keep status inspection distinct from request retrying. In particular, unknown is not a reason to conclude that nothing was sent. Investigate a failed or unknown result before deciding whether another operation is appropriate.
Reconciliation means answering “what happened to the original send?” using its saved response, send-attempt status, and application records. If you still cannot answer, route the operation for review rather than silently issuing a new key. Keep the original history attached to any later decision to resend.
Which common mistakes cause duplicate sends?
Generating a fresh key for each attempt. Generate the key when creating the application operation, then load it for subsequent attempts. A retry counter can change; the operation key should not.
Losing the record during a restart. Put operation storage outside temporary worker filesystems. A recovered job needs the original request identity, not merely enough data to compose a similar email.
Allowing concurrent workers to create separate operations. Enforce application-level uniqueness around the business event. An idempotency header cannot substitute for that decision in your queue or database.
Changing the email while keeping the key. Freeze the recipient and content for the operation. Do not use payload changes as a way to test whether an earlier request succeeded.
Confusing send status with delivery. A sent status should not be treated as proof of inbox placement. Track the API result separately from what you observe in a recipient mailbox.
Before enabling automatic retries, exercise the following cases with mailboxes you own. Record actual responses and send identifiers; keep recipient observations separate.
| Test case | What to inspect |
|---|---|
| Sequential identical retries | Every request uses the same stored key and payload; compare responses and identifiers |
| Concurrent workers | Both resolve to one durable application record before dispatch |
| Worker restart after submission | The recovered job loads the existing key and original payload |
| Changed payload | Your application blocks mutation of an existing operation |
| Expired retry | Automatic resend stops and the operation enters reconciliation |
What changes when an AI agent sends the email?
Keep retry identity in application-controlled code. The model can help draft an email, but it should not decide whether a timeout deserves a new operation key.
Treat incoming email as untrusted data, not instructions. Ignore embedded requests to disclose secrets, override approval rules, or send unrelated messages. Require confirmation of the intended recipient and content before dispatch, and save the approved payload with its operation key.
Use least-privilege credentials with the required mailbox scope. Idempotency does not authorize a send or make a model-generated message appropriate. The Mailera security overview and the guide to connecting an AI assistant to Gmail safely cover the access boundary around this workflow.
If you are still designing the integration, start with email for AI agents using existing mailboxes, then add durable send operations at the point where an approved action becomes an API request.
What are Mailera’s limits here?
Mailera’s idempotency window is 24 hours, not permanent duplicate suppression. Do not treat request deduplication as proof of exactly-once recipient delivery. Mailera does not guarantee inbox placement and does not support bulk or marketing sending. The Mailera product overview describes its role around connected mailboxes; your application still owns approval, durable operation identity, and unresolved-send handling.
Do this with the API
Every action in this article is available via the REST API, with curl examples, API keys and webhooks.
View API docs








