Pre-Black Friday: 20% off, for as long as you stayEARLYBFon Solo and AgencyEnds Nov 28Start free

How-to guide

How to Decide How Long to Warm Up Email (2026 Ramp)

No provider publishes a fixed warm-up length. Here is a ramp you can script, the signals that tell you to stretch it, and the list size it needs.

Get your free API key →Free to start. No credit card. 1,000 records to spend whenever you like.

A new mailbox needs about 14 days to reach 100 messages a day, and 28 days if bounces or spam placement say slow down. We know of no mailbox provider that publishes a fixed number of days. The length is a result of your bounce rate, not a calendar target.

This guide gives you a ramp as code, a rule that stretches it, and the list size it needs.

TL;DR

  • Plan 14 days to reach 100 messages a day. Add days whenever bounces rise instead of pressing on.
  • The 14-day ramp sends 700 messages. Pulling and enriching 700 people spends about 1,400 LeadOcean records, so the 1,000 free records cover the first 12 days.
  • Sizing the list with a count call is free. Only the daily pulls spend records.

Prerequisites

  • A sending domain and mailbox, with access to DNS.
  • A sender that caps messages per day (your own SMTP or any sequencer).
  • A LeadOcean API key as $LEADOCEAN_API_KEY. Start free at app.leadocean.io, no card.
  • Python 3 with requests, and curl.

Step 1: Authenticate the domain first

Warm-up time starts only after SPF, DKIM and DMARC pass. Google's sender guidelines ask all senders for SPF or DKIM, and senders of 5,000 or more messages a day for SPF, DKIM and DMARC. Google recommends all three for every domain (source, October 2026).

bash
dig TXT acme-outreach.com +short
dig TXT _dmarc.acme-outreach.com +short

If either returns nothing, fix DNS before day 1. Google says unauthenticated messages might be marked as spam or rejected, so treat those days as lost.

Step 2: Write the ramp as code

A ramp is a list of daily caps. This one is our example, not a provider rule. It reaches 100 a day in 14 days.

python
RAMP = [5, 10, 15, 20, 25, 30, 40, 50, 60, 70, 80, 90, 100, 100]

def cap_for(day: int) -> int:
    return RAMP[min(day, len(RAMP)) - 1]

if __name__ == "__main__":
    print(sum(RAMP), "messages over", len(RAMP), "days")
bash
python3 ramp.py
700 messages over 14 days

That total sets your record budget. Each person a search returns counts one record, and each enrichment that returns a person counts one more.

Step 3: Add the rule that stretches it

The ramp length is the number of days the stop rule lets it run. Check yesterday's bounce rate before you raise the cap, and hold the cap when it is high.

python
def next_day(day: int, sent: int, bounced: int, limit: float = 0.02) -> int:
    """Advance only when yesterday's bounce rate is at or under the limit."""
    if sent and bounced / sent > limit:
        return day  # hold today's cap
    return day + 1

print(next_day(day=6, sent=30, bounced=2))   # 6.7% bounce: stays on day 6
print(next_day(day=6, sent=30, bounced=0))   # advances to day 7

The 2% line is ours. Pick your own, and add a second hold for low reply rates or spam placement in test inboxes. Each hold adds a day. A clean list can finish in 14. A dirty one keeps holding.

Step 4: Size a verified list for free

Bounces are the main reason a ramp stretches, so start from verified addresses. Count first. A count spends no records.

bash
curl -s -G "https://api.leadocean.io/v1/people/search" \
  -H "x-api-key: $LEADOCEAN_API_KEY" \
  --data-urlencode "jobLevel=VP" \
  --data-urlencode "jobFunction=Sales & Business Development" \
  --data-urlencode "country=GB" \
  --data-urlencode "emailStatus=verified" \
  --data-urlencode "count=true" \
  --data-urlencode "limit=1"

count=true goes in the query string with limit=1, and the data array comes back empty. The MCP tool leadocean_count_leads takes the same filters and is also free. Filter on emailStatus=verified, because the default count includes catch-all addresses.

Step 5: Pull each day's quota

Fetch only today's cap. Save the cursor so tomorrow continues where today stopped.

python
import os, json, requests
from ramp import cap_for

API = "https://api.leadocean.io/v1/people/search"
day = int(os.environ.get("RAMP_DAY", "1"))
want = cap_for(day)
body = {
    "jobLevel": ["VP"],
    "jobFunction": ["Sales & Business Development"],
    "country": ["GB"],
    "emailStatus": ["verified"],
    "limit": min(want, 100),
}
r = requests.post(API, json=body, headers={"x-api-key": os.environ["LEADOCEAN_API_KEY"]})
r.raise_for_status()
page = r.json()
json.dump(page["data"], open(f"day_{day}.json", "w"))
print(f"day {day}: cap {want}, pulled {len(page['data'])}")

Set RAMP_DAY from the next_day result in Step 3. For caps above 100, loop with meta.nextCursor as the cursor field. To get the address, enrich each row by its meta.source_ids.person_id with reveal_email (POST /v1/people/enrich). Each enrichment is one record; the reveal costs no extra record.

What you get

The free count for Step 4, run with the MCP tool leadocean_count_leads on 2026-10-21. It counts verified emails only, not everyone matching the other filters.

json
{
  "total": 918,
  "totalIsExact": true,
  "distinctCompanies": 710,
  "credits": 0,
  "unsupportedFilters": []
}

918 verified UK sales VPs covers the 700 the ramp needs. A 28-day ramp at the same peak needs more, so count a wider cut before you start.

Response shape from the API reference, with placeholder values.

json
{
  "data": [ { "profile_data": { "profile_full_name": "Jane Doe" }, "contact_data": { "has_email": true, "email_status": "verified" }, "meta": { "source_ids": { "person_id": "1234567" } } } ],
  "meta": { "count": 5, "limit": 5, "nextCursor": "opaque-cursor-string", "credits": 5 }
}

Troubleshooting

ErrorCauseFix
401Missing or wrong x-api-keyRe-export $LEADOCEAN_API_KEY and check the header name
429Above the plan's rate limit (5 requests a second on Free, 200 on Agency)Wait for Retry-After, then retry
402Out of records (Free is 1,000 for life)Shorten the ramp or move to Solo at $97 a month
Empty dataA filter value that is not an exact enum stringCheck with leadocean_list_enum_values or GET /v1/enums
No nextCursorThe search paged to 10,000 rows (meta.depthCapped)Narrow the filters and run a second search
Export refusedOver 50,000 rows a request or 500,000 a daySplit into smaller requests

FAQ

How many days does it take to warm up an email address?

Plan 14 days to reach 100 messages a day and expect up to 28 if bounces rise. That is our working rule, not a provider limit. See the warm-up schedule tools for tools that automate the cap.

Can I shorten the ramp?

Only by sending to cleaner addresses. A faster schedule on an unverified list raises bounces and lengthens the ramp. Pass emailStatus=verified and read email_status before sending, because bounced emails are not refunded.

Does LeadOcean warm up my mailbox?

No. LeadOcean is a data API with an MCP server. It has no sender, inbox network or sequencer. It supplies the addresses. For the full scripted setup see automated email warm-up.

Which warm-up tool should I use?

Compare options in our cold email warm-up tools roundup. Any tool that caps daily volume works with this ramp.

What does it cost?

Free covers 1,000 records for life, enough for the first 12 days of this ramp (about 990 records). Solo is $97 a month and Agency $497 a month, with a fair-use pace instead of credits. See pricing.

Warm the mailbox on a list that will not bounce

Free to start. No credit card. 1,000 records to spend whenever you like.

Get your free API key →