Skip to main content

Errors and Rate Limits

Sending email at scale means dealing with errors. This page covers what Mailtarget returns, what you should retry, and what should fail fast and surface to a human.

API error response shape

When the API returns a non-2xx status, the body is a JSON object with two fields.

{
"error": "string code",
"message": "human-readable description"
}

The error field is a stable code you can match against in code. The message field is for humans and may change.

HTTP status codes

StatusMeaningWhat to do
200 / 201Accepted. Response body contains the transmissionId.Persist the transmissionId and listen for webhook events.
400 Bad RequestThe request body is malformed or a required field is missing.Do not retry. Fix the request and resubmit.
401 UnauthorizedThe Authorization header is missing, malformed, or the key is invalid.Do not retry. Check the header and the key.
403 ForbiddenThe key is valid but the scope does not cover this operation, or the request came from an IP outside the allowlist.Do not retry. Check the key permission scope and the allowlist.
404 Not FoundThe endpoint path is wrong, or a referenced resource (template ID, contact ID) does not exist.Do not retry. Check the URL and resource identifiers.
422 Unprocessable EntityThe request is well-formed but business validation failed (for example, recipient on suppression list, sending domain not verified).Do not retry. Surface to a human.
429 Too Many RequestsYou exceeded a rate limit.Retry after the duration in the Retry-After header.
500 Internal Server ErrorMailtarget had an internal failure.Retry with exponential backoff.
502 / 503 / 504Transient infrastructure issue (gateway, upstream, timeout).Retry with exponential backoff.

Rate limits

The API enforces per-account rate limits. When you exceed one, the response status is 429 and the response includes a Retry-After header indicating the number of seconds to wait before retrying.

HTTP/1.1 429 Too Many Requests
Retry-After: 30
Content-Type: application/json

{ "error": "rate_limited", "message": "Account send rate exceeded." }

Honor Retry-After. Do not retry sooner. Most rate limits resolve in seconds; a few resolve in minutes. The exact ceiling depends on your account package and is visible in the dashboard.

If you hit 429 repeatedly, the throughput your account is provisioned for is below your demand. Either:

  • Reduce the send rate at the application layer (queue and drain).
  • Raise the package ceiling.

Do not work around 429 by spinning up more keys or sending from more IPs. The limit is per account, not per key.

Retry strategy

A safe retry policy:

  • Retry only 429, 500, 502, 503, 504.
  • Use exponential backoff with jitter. A common starting point is 2 ** attempt + random(0, 1) seconds, capped at 60 seconds.
  • Cap retries at five attempts. After the cap, write the request to a dead-letter queue for human review.
  • Persist the request body and an idempotency key (you choose the key) before the first attempt. On retry, send the same idempotency key in the request metadata so duplicate sends can be deduped at reconciliation time.

Do not retry 400, 401, 403, 404, 422. Those are caller errors. Retrying them just amplifies the problem.

SMTP errors

The SMTP relay returns standard SMTP response codes.

Code classMeaningWhat to do
2xxAccepted by the relay.Treat as queued for delivery. Listen for webhook events for final state.
4xxTemporary failure.Retry with backoff. Most SMTP clients do this automatically.
5xxPermanent failure.Do not retry. Surface to a human. The bounce will also fire as a webhook event.

The relay returns the same kinds of failure modes as the API: bad credentials, unverified domain, suppressed recipient, rate exceeded. The codes follow RFC 5321. The text in the response body tells you which class.

Bounce types

Mailtarget classifies non-deliveries into two categories that affect retry behavior:

  • Hard bounce. The recipient is permanently undeliverable (mailbox does not exist, domain does not accept mail). Mailtarget adds the address to the suppression list. Do not retry. Read the Operations section on bounce classification for the policy.
  • Soft bounce. The recipient is temporarily undeliverable (mailbox full, server unavailable, greylisting). Mailtarget retries automatically inside the platform for a bounded window. Your application does not need to retry soft bounces.

Treat the suppression list as authoritative. Sending to addresses on the list is a fast way to damage your sending domain reputation.

Reconciling sends to outcomes

The handle is the transmissionId returned at submit time. Every webhook event for that send carries the same transmissionId. Persist the ID at the moment you get the 2xx response, and join against webhook events as they arrive.

If you do not get a transmissionId (because the response was an error), the send did not happen. Treat it as not yet sent.

Next

Wire Webhooks to receive delivery, open, click, bounce, and complaint events. Without webhooks, you cannot tell what happened after submit.