Email Warmup API: Start, Pause and Monitor
How to run mailbox warm-up through the Outreach2day email warmup API: enable, pause and disable operations, idempotency keys, polling and warm-up states.
On this page
An email warmup API lets you start, pause and check mailbox warm-up from code instead of a dashboard. That matters once you manage mailboxes in batches: a new client's mailboxes should start warming the day they are ready, a mailbox with problems should stop, and your own tools should know which mailboxes are still warming.
This article covers the three warm-up endpoints of the Outreach2day API, with curl and Python examples. It assumes you have an API key and a workspace ID; the cold email API overview explains both. The curl examples use two shell variables:
export O2D="https://public.outreach2day.com"
export O2D_KEY="ot2d_your_key"
What Warm-Up Does and How Long It Takes
Warm-up sends a small, growing number of emails between a new mailbox and other mailboxes that open and reply to them. Mailbox providers see a sender with a normal history before any cold email goes out. The email warm-up service article explains the mechanism, and the warm-up tools comparison lists the options.
Plan for at least two weeks of warm-up before a new mailbox sends cold email (see how long to warm up before sending), and keep warm-up running while the mailbox sends.
Email Warmup API Endpoints
Endpoint | What it does |
|---|---|
| Starts an operation: |
| Returns the operation's status and a result per mailbox |
| Returns the current warm-up state of every mailbox in the workspace |
All three use the query parameter workspaceId and the header Authorization: Bearer ot2d_....
Warm Up Inboxes via API in Batches
The request body needs an action, the mailboxes and an idempotencyKey:
curl -X POST "$O2D/warmup/operations?workspaceId=123" \
-H "Authorization: Bearer $O2D_KEY" \
-H "Content-Type: application/json" \
-d '{
"action": "enable",
"mailboxes": [
"anna@acmemail.com",
"ben@acmemail.com"
],
"idempotencyKey": "client-a-enable-2026-09-28"
}'
The response is the operation:
{
"operationId": "...",
"status": "requested",
"action": "enable",
"workspaceId": 123,
"requestedCount": 2,
"prevalidatedCount": 2,
"acceptedCount": 0,
"rejectedCount": 0,
"successCount": 0,
"failureCount": 0,
"rejections": [],
"items": [
{
"mailboxId": 501,
"mailbox": "anna@acmemail.com",
"status": "requested"
}
]
}
Items carry more fields (timestamps, errorCode, errorMessage); the example is shortened.
Select Mailboxes by Filter Instead of by Address
For a whole domain, you can send a target instead of a list of addresses. With "mode": "all_filtered", the operation applies to every mailbox that matches the filters, for example all mailboxes on one domain:
{
"action": "enable",
"target": {
"mode": "all_filtered",
"filters": {"domainId": [101]}
},
"idempotencyKey": "enable-domain-101-2026-09-28"
}
Filters also accept status, warmupState, tagId and search, and you can leave out mailboxes with excludedMailboxes. The domain IDs come from GET /domains?workspace_id=123.
Idempotency Keys
idempotencyKey is required and must be 8 to 128 characters. If a request with the same key already created an operation in the workspace, the API returns that operation instead of starting a new one. So when a request times out and you are not sure it arrived, send it again with the same key.
The key is matched per workspace, whatever the body says: a second request with the same key but a different action or mailbox list returns the first operation and does nothing. Build one key per batch, for example the client, the action and a batch number or a short hash of the addresses. Do not generate a new random key per attempt, or a retry starts a second operation.
Poll the Operation Until It Finishes
Warm-up changes are applied in the background. Poll GET /warmup/operations/{operation_id} while status is requested or processing. Every other status is final:
Final | Meaning |
|---|---|
| The mailboxes were admitted to warm-up. For |
| Every mailbox in the operation succeeded |
| Part of the batch went through: some mailboxes were rejected or failed |
| The operation did not complete |
| The result is unclear and is being checked |
An operation result says the request went through. To see whether a mailbox is actually warming, read GET /warmup/mailboxes (below), where its warmupState becomes warming.
In Python, with the api() helper from the API overview:
import time
WS = 123
op = api("POST", "/warmup/operations",
params={"workspaceId": WS},
json={
"action": "enable",
"mailboxes": ["anna@acmemail.com"],
"idempotencyKey": "client-a-enable-001",
})
RUNNING = {"requested", "processing"}
while op["status"] in RUNNING:
time.sleep(10)
op = api("GET",
f"/warmup/operations/{op['operationId']}",
params={"workspaceId": WS})
print("operation", op["status"])
for r in op["rejections"]:
print("rejected", r["mailbox"], r["code"])
Rejected Mailboxes
Mailboxes that cannot take the action are listed in rejections with a code, and the rest of the batch goes ahead:
| Cause |
|---|---|
| The address is not a mailbox in this workspace |
| The mailbox status does not allow warm-up (for example, it is still being set up or is deactivated) |
Warm-up accepts mailboxes whose status is active, warmup_in_progress, warmup_paused or warmup_error. If every mailbox is rejected, the operation ends as failed.
A request with no valid addresses returns 400.
Pause, Disable or Remove Warm-Up
The same endpoint handles the other actions:
pausestops warm-up for now. Use it while you investigate a mailbox, then sendenableagain.disableturns warm-up off for the mailbox.removeremoves the mailbox from warm-up. It is the only action that also accepts mailboxes whose status blocks the other actions, such as deactivated ones.
curl -X POST "$O2D/warmup/operations?workspaceId=123" \
-H "Authorization: Bearer $O2D_KEY" \
-H "Content-Type: application/json" \
-d '{
"action": "pause",
"mailboxes": ["ben@acmemail.com"],
"idempotencyKey": "pause-ben-2026-09-28"
}'
Read the Warm-Up State of Every Mailbox
GET /warmup/mailboxes returns one row per mailbox:
curl "$O2D/warmup/mailboxes?workspaceId=123" \
-H "Authorization: Bearer $O2D_KEY"
[
{
"mailboxId": 501,
"mailbox": "anna@acmemail.com",
"mailboxStatus": "active",
"warmupState": "warming",
"warmupEnabled": true,
"warmupStartedAt": "2026-09-14T09:12:00Z",
"warmupPausedAt": null,
"latestOperationId": "...",
"latestOperationStatus": "completed"
}
]
The rows have a few more fields; the example is shortened. warmupState is one of not_started, warming, paused, error or disabled. warmupStateReason is set when the last observation of the mailbox is out of date (provider_observation_stale).
A report of mailboxes that have warmed for 14 days or more, or that need attention:
from datetime import datetime, timezone
rows = api("GET", "/warmup/mailboxes",
params={"workspaceId": 123})
now = datetime.now(timezone.utc)
for m in rows:
started = m.get("warmupStartedAt")
days = 0
if started:
t = datetime.fromisoformat(
started.replace("Z", "+00:00"))
if t.tzinfo is None:
t = t.replace(tzinfo=timezone.utc)
days = (now - t).days
ready = m["warmupState"] == "warming" and days >= 14
flag = "ready" if ready else m["warmupState"]
print(m["mailbox"], days, flag)
Fourteen days is the minimum. Before a mailbox sends cold email, also check its DNS with the SPF, DKIM and DMARC test, then add the mailboxes to Instantly or Smartlead if you send from there. To run these calls from Claude with an approval step, see the MCP server for email warmup.
FAQ
Does the API choose the warm-up volume?
No. The API turns warm-up on, off or into pause; daily warm-up volume is managed by Outreach2day and is not a request field.
Does the API return a reputation score or inbox rate?
No. It returns warm-up state (warmupState, warmupStartedAt, the latest operation), not a score. Mailbox analytics are in the app.
Should warm-up stay on while I send?
Yes. Keep it running while the mailbox sends cold email; it is included in the mailbox price.
How often should I poll?
Every few seconds for an operation you just started, and once a day or less for GET /warmup/mailboxes. The API allows 10 requests a second and 300 a minute per user and per workspace.
Can I start warm-up on mailboxes that are not in Outreach2day?
No. Operations only apply to mailboxes in the workspace; other addresses come back as MAILBOX_NOT_FOUND.
Is warm-up included in the price?
Yes. Warm-up is included in the per-mailbox price on every plan; see pricing.
Get Started
Create an account and order mailboxes in the app, then create a key on the API keys page and start warm-up with the request above.
Keep reading
Send 100,000 cold emails a month
How to send 100,000 cold emails a month while keeping quality, engagement and conversion rates high: domains, mailboxes, warm-up, leads, copy and scaling.
Step-by-step playbook · 19 min readEmail tools8 min read
Cold Email API for Domains, Warm-Up and Replies
Email tools7 min read
MCP Server for Email Warmup With Claude
Email tools5 min read
Add Email Accounts to Instantly or Smartlead via API

