MailLandDocs

Rate Limits

Understand API rate limits, email sending limits, and how to handle rate-limited responses

MailLand enforces rate limits at multiple levels to ensure fair usage and platform stability. Limits vary by stream type (transactional vs marketing), authentication method, and plan tier.

API Request Limits

IP-Based Limits

Every request is subject to IP-based rate limiting, applied before authentication. These limits protect against abuse and DDoS attacks.

EndpointLimitWindow
General API300 requestsPer minute
Admin login10 requestsPer minute
Team invitations10 requestsPer minute
SSO domain checks15 requestsPer minute

User (non-admin) login is not governed by this IP window: see Login Rate Limiting below for the 5-attempts/15-minute lockout that applies to it.

IP-based limits apply per source IP address. If you operate behind a shared proxy, all clients share the same limit.

Login Rate Limiting

Failed login attempts are tracked per IP + email combination:

ParameterValue
Max failed attempts5
Tracking window15 minutes
Lockout duration15 minutes

After 5 failed login attempts within 15 minutes, the IP + email pair is locked out for 15 minutes. Successful login resets the counter.

API Key Authentication

Failed API key authentication attempts are tracked in two dimensions:

DimensionMax FailuresWindowBlock Duration
Per key prefix10 attempts15 minutes15 minutes
Per IP address20 attempts15 minutes15 minutes

If either dimension exceeds its threshold, authentication is temporarily blocked.

Email Sending Limits

Email sending limits are enforced per workspace and vary by stream type. Transactional emails (receipts, password resets) get higher limits than marketing emails (newsletters, campaigns). Per-minute is the value that actually comes from your plan (see Policy Summary); per-second and per-hour are derived from it, not set independently, and only day/month use fixed platform defaults.

Transactional Stream

WindowHow it's derived
Per secondPlan's per-minute rate ÷ 60 (minimum 1); one request of up to 5 recipients is accepted in a second with no other accepted request, see below
Per minuteFrom your plan (TransactionalRatePerMin)
Per hourPlan's per-minute rate × 60
Per day1,000,000 (platform default)
Per month10,000,000 (platform default)

Requests with several recipients. Every recipient counts against every window. A transactional request (at most 5 recipients) whose recipient count is above your per-second allowance is still accepted if no other request was accepted in that second; another request in the same second gets 429 with Retry-After: 1. For example, on a plan of 60 per minute (1 per second), one request to 3 recipients is accepted, and another request in that second is refused until the next second. The per-minute, per-hour, per-day and per-month limits, warm-up and your monthly quota still count all 3 recipients. SMTP applies the same rule to each message, counting its unique RCPT TO addresses.

Marketing Stream

WindowHow it's derived
Per secondNot checked: marketing sends always skip the per-second check, batch or not
Per minuteFrom your plan (MarketingRatePerMin)
Per hourPlan's per-minute rate × 60
Per day100,000 (platform default)
Per month1,000,000 (platform default)

Per-minute rates are plan-specific: check your current limits via the Billing page, which surfaces the GET /v1/account/subscription/policy-summary API route.

Stream Priority

Transactional emails have higher priority (priority 1) than marketing emails (priority 2). When the system is under load, transactional emails are processed first.

Batch Operations

Batch sending operations (e.g. POST /v1/transactional/send-batch) are marketing-only and skip per-second rate checks the same way every marketing send does, but they are still subject to per-minute, per-hour, per-day, and per-month limits.

Workspace Sending Limits

Verification level does not set a volume cap: it gates which features are available. Your daily/monthly send volume comes from your plan (see Policy Summary), not from your verification level.

Verification LevelTransactionalMarketingInbound
SandboxAllowlisted recipients onlyNoNo
BasicVerified / SenderVerifiedYesNoYes
BusinessVerifiedYesYesYes

Workspace limits are checked before stream rate limits. You can view your current limits and usage on the Billing page, which is backed by GET /v1/account/subscription/policy-summary.

IP Warmup

Warmup is per plan family, not a fixed schedule. Free plans run 6 stages of 5 days each (50 → 100 → 250 → 500 → 750 → 1,000/day) for 30 days total; Pro plans run 500 → 1,000 → 2,500 → 5,000 → 10,000 → 25,000/day over 14 days; Max plans have no warmup. See your plan's warmup schedule via the Billing page above.

Rate Limit Headers

Most API responses include:

HeaderDescription
X-RateLimit-LimitMaximum requests allowed in the current window
X-RateLimit-RemainingRequests remaining in the current window

An IP-based 429 additionally includes:

HeaderDescription
X-RateLimit-ResetISO-8601 UTC timestamp when the current window resets
Retry-AfterNumber of seconds to wait before retrying

Handling 429 Responses

When you receive a 429 Too Many Requests response, the body contains details about which limit was exceeded:

Rate limit error response
{
  "code": "IP_RATE_LIMIT_EXCEEDED",
  "message": "Too many requests from this IP. Retry after 45 seconds.",
  "details": {
    "limit": 300,
    "current": 301,
    "retryAfter": 45,
    "resetAt": "2026-02-18T12:35:00Z"
  }
}

For email sending rate limits:

Email rate limit response
{
  "code": "RATE_LIMIT_EXCEEDED",
  "message": "Per-minute rate limit exceeded (transactional)"
}

The message text above is an example: it's generated from the policy engine's decision reason and is not a guaranteed literal string. Match on code, not message.

Retry Strategy

retry-with-backoff.sh
#!/bin/bash
MAX_RETRIES=3
ATTEMPT=0

while [ $ATTEMPT -le $MAX_RETRIES ]; do
  RESPONSE=$(curl -s -D - -o /tmp/body -w "%{http_code}" -X POST https://api.mail.land/v1/transactional/send \
    -H "X-API-Key: ml_pet_Ab3Kx9mN2pQ7rT4wL8yD..." \
    -H "Content-Type: application/json" \
    -d '{ "from": {"email": "[email protected]"}, "to": [{"email": "[email protected]"}], "subject": "Hello", "htmlContent": "<p>Hi</p>" }')

  HTTP_CODE=$(echo "$RESPONSE" | tail -n1)

  if [ "$HTTP_CODE" -ne 429 ]; then
    cat /tmp/body
    exit 0
  fi

  # Read the Retry-After header, not the response body - not every 429 has a `details` block.
  RETRY_AFTER=$(echo "$RESPONSE" | grep -i '^Retry-After:' | tr -d '\r' | cut -d' ' -f2)
  RETRY_AFTER=${RETRY_AFTER:-60}
  ATTEMPT=$((ATTEMPT + 1))
  echo "Rate limited. Retrying in ${RETRY_AFTER}s (attempt ${ATTEMPT}/${MAX_RETRIES})"
  sleep "$RETRY_AFTER"
done

echo "Max retries exceeded"
exit 1

Best Practices

Monitor your usage. Check the X-RateLimit-Remaining header proactively to throttle requests before hitting limits.

Use exponential backoff. When retrying after a 429, always respect the Retry-After header. If not present, use exponential backoff starting at 1 second.

Prefer batch endpoints. For high-volume sending, use POST /v1/transactional/send-batch instead of calling POST /v1/transactional/send in a loop. Batch endpoints skip per-second checks and are more efficient.

Separate transactional and marketing. Use separate API credentials for transactional and marketing emails. This ensures marketing sending never impacts transactional delivery.

Distribute sending over time. For large campaigns, MailLand automatically paces delivery. For API-driven bulk sends, spread requests evenly rather than sending in bursts.

Password Reset Limits

Password reset requests have separate rate limits:

ParameterValue
Cooldown between requests60 seconds
Max requests per day5

Next Steps

  • Error Codes: complete error code reference
  • API Keys: create and manage API credentials
  • Billing: view your current usage and limits

On this page