Error Codes
Complete reference of Mail.Land API error codes and their meanings
Every error response from the MailLand API includes a code field with a machine-readable error code and a message field with a human-readable description.
Error Response Format
{
"code": "DOMAIN_NOT_VERIFIED",
"message": "Domain is not verified",
"timestamp": "2026-02-18T12:35:00Z",
"traceId": "00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01"
}Some errors include additional details:
{
"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"
}
}Request Validation (400)
Returned when the request body, query parameters, or headers are malformed or missing required fields.
| Code | Description |
|---|---|
INVALID_REQUEST | General invalid request |
VALIDATION_FAILED | One or more fields failed validation |
INVALID_EMAIL_FORMAT | Email address format is invalid |
WEBHOOK_DESTINATION_NOT_ALLOWED | A webhook URL is refused by the destination policy: webhooks are delivered over HTTPS on port 443 only and may not point at MailLand's own servers, addresses or host names |
MISSING_CONTENT | Deprecated as of 2026-04. Use VALIDATION_FAILED: send/scheduled endpoints now return structured validation errors. |
CONTENT_TOO_LARGE | Payload exceeds the maximum allowed size. POST /v1/transactional/send and send-batch return it as 413 when the assembled message would exceed the platform's message-size limit (message: "The message is too large to send: it would exceed the platform's message-size limit. Reduce the HTML, text, attachments or recipients."): nothing is queued; shrink the message and resend. CSV imports return it as 400 |
transactional_recipient_limit_exceeded | More than 5 recipients on a transactional credential (lowercase code) |
marketing_recipient_limit_exceeded | More than 1,000 recipients on a marketing credential (lowercase code) |
VALIDATION_FAILED | Batch send with more than 10,000 recipients |
SEND_FAILED | Email send operation failed, including "all recipients are suppressed" |
BATCH_SEND_FAILED | Batch send operation failed |
IDEMPOTENCY_KEY_INVALID | Idempotency key is empty, malformed, over 255 characters, or the header was sent more than once (send/send-batch only) |
IDEMPOTENCY_KEY_CONFLICT | X-Idempotency-Key header and idempotencyKey body field were both supplied and differ |
INVALID_CURSOR | Cursor pagination parameter is malformed |
PASSWORD_REQUIRED | Password confirmation is required |
RECIPIENT_SUPPRESSED | Recipient is on the suppression list |
Authentication (401)
Returned when the request is missing credentials or the credentials are invalid.
| Code | Description |
|---|---|
UNAUTHORIZED | Missing, invalid, expired or revoked X-API-Key: the API key middleware returns this single code for every case, with a descriptive message. It does not distinguish missing/invalid/expired/revoked by code. A wrong login password also returns 401 UNAUTHORIZED. |
LOGIN_REQUIRED | Login is required for this operation |
Two-Factor Authentication
2FA failures return 400 INVALID_REQUEST with a descriptive message (e.g. "Invalid code", "2FA is already enabled"). There are no dedicated 2FA error codes, read the message field.
Authorization (403)
Returned when the authenticated user does not have permission to perform the requested action.
| Code | Description |
|---|---|
FORBIDDEN | General access denied |
INSUFFICIENT_PERMISSIONS | User lacks the required role or permission |
ACCOUNT_SUSPENDED | User account has been suspended |
ACCOUNT_DISABLED | User account has been disabled |
ACCOUNT_NOT_ACTIVE | User account is not active |
IP_NOT_ALLOWED | Client IP is not in the credential's allowed list |
VALIDATION_CREDENTIAL_REQUIRED | A Validation API key is required for the email validation endpoints. A Sending or Inbound key is refused; a signed-in session or a Validation-product key is accepted |
PLAN_LIMIT_REACHED | Plan resource limit reached: upgrade required |
SENDING_BLOCKED | Account verification level does not allow this send. Note: the policy engine's own SendingBlocked refusal is 403; the same code from the rate/warmup policy path is 429, see the Policy Engine section below. |
SUBSCRIPTION_EXPIRED | Subscription has expired |
NO_ACTIVE_SUBSCRIPTION | No active subscription found |
TENANT_APPROVAL_REQUIRED | The account is awaiting review before it can send ("Your account is awaiting review before it can send…"). Retrying does not help; contact support if the review takes longer than expected |
MARKETING_NOT_YET_ALLOWED | Marketing email is not open yet. It opens automatically once the account has a clean transactional history: at least 500 delivered transactional emails over at least 7 days, hard bounces under 2% and complaints under 0.1%. A campaign deferred by it stays pending |
MARKETING_SUSPENDED | Marketing email is temporarily unavailable platform-wide. Transactional email is not affected; campaigns and automations are kept and resume when marketing is enabled |
ACTION_REQUIRED | User action is required before sending can resume. Also returned for every send while a workspace has an active deliverability hold (bounce/complaint-rate breach): SMTP relay returns 550 for the same hold. See Deliverability Holds |
Not Found (404)
Returned when the requested resource does not exist or belongs to a different workspace.
| Code | Description |
|---|---|
RESOURCE_NOT_FOUND | Generic resource not found |
USER_NOT_FOUND | User does not exist |
WEBHOOK_NOT_FOUND | Webhook does not exist |
DELIVERY_NOT_FOUND | Webhook delivery does not exist |
Most 404 responses use the RESOURCE_NOT_FOUND code. The message field provides context about which resource was not found (e.g. "Domain not found", "Template not found", "Campaign not found"). Webhook endpoints are the exception: retrying a webhook delivery uses WEBHOOK_NOT_FOUND / DELIVERY_NOT_FOUND instead.
Conflict (409)
Returned when the operation conflicts with the current state of the resource.
| Code | Description |
|---|---|
CONFLICT | General resource conflict |
IDEMPOTENCY_KEY_REUSED | Idempotency key already in use for a different endpoint on this account (send/send-batch only) |
Domain and Sending (422)
Returned when the request is well-formed but cannot be processed due to business logic constraints.
| Code | Description |
|---|---|
DOMAIN_NOT_FOUND | Domain does not exist in the workspace |
DOMAIN_NOT_VERIFIED | Domain has not been verified, complete DNS setup first |
DOMAIN_NOT_ALLOWED_FOR_CREDENTIAL | Credential is not authorized for this sender domain |
CAMPAIGN_LINK_BLOCKED | A link in a campaign points at a destination flagged as unsafe; the campaign is not scheduled or sent |
DOMAIN_SUSPENDED | Domain has been suspended |
DOMAIN_VERIFICATION_EXPIRED | Domain verification has expired: re-verify |
Payment Required (402)
Returned when the workspace's credit balance cannot cover the requested operation.
| Code | Description |
|---|---|
INSUFFICIENT_CREDITS | Not enough credits to complete the operation |
Rate Limiting (429)
Returned when the request exceeds rate limits. Usually includes a Retry-After header; if it is absent, back off exponentially rather than assuming no wait is needed.
API Rate Limits
| Code | Description |
|---|---|
RATE_LIMIT_EXCEEDED | General API rate limit exceeded |
IP_RATE_LIMIT_EXCEEDED | IP-based rate limit exceeded |
SUPPORT_RATE_LIMITED | Support API rate limit exceeded |
TOO_MANY_LOGIN_ATTEMPTS | Too many failed login attempts, locked out temporarily |
Email Sending Rate Limits
| Code | Description |
|---|---|
DAILY_LIMIT_EXCEEDED | Daily email sending limit exceeded |
WARMUP_LIMIT_EXCEEDED | The account's daily ramp-up limit for new sending was reached; resets at 00:00 UTC (see IP Warmup) |
PAYMENT_DAILY_LIMIT_EXCEEDED | Daily limit reached on a past-due account |
Platform Capacity (429)
These refusals mean the platform, not your account quota, is limiting new sends right now. Each one is a 429 with a Retry-After header, nothing was queued, and it is safe to retry the same request. Over SMTP the same refusals are a transient 421 Try again later: <message>.
| Code | message (as returned) | When to retry |
|---|---|---|
WARMUP_POOL_BUDGET_EXCEEDED | Sending is temporarily paused for today. It resumes automatically at 00:00 UTC; no action is needed. | After Retry-After (the next 00:00 UTC) |
WARMUP_POOL_BUDGET_EXCEEDED | Sending is briefly delayed. Please retry in a few minutes. (same code, when platform capacity cannot be verified for a moment) | After the short Retry-After |
WARMUP_POOL_EMPTY | Sending is temporarily paused. It resumes automatically; no action is needed. | After Retry-After; no action needed |
PLATFORM_DAILY_CAPACITY_REACHED | Platform sending capacity for today is fully booked. This is a temporary platform-wide limit, not your account quota, and it resets at midnight UTC. | After Retry-After (the next 00:00 UTC) |
PLATFORM_CAPACITY_PROTECTION | New sending is briefly paused to protect platform capacity. Mail already accepted is not affected. This is transient and clears on its own; retry shortly. | After the short Retry-After |
PROBATION_CAP_REACHED | New accounts can send to <N> recipients per rolling 24 hours until our team has reviewed the account. Capacity returns as earlier sends age out of the 24-hour window; contact support to request a review. (or …cannot be verified right now, so sending is briefly paused… for a momentary outage) | After Retry-After, or ask support for a review |
Mail that was already accepted is never affected by these refusals. Treat them like any other 429: back off, honour Retry-After, and retry. There is nothing to configure or upgrade.
Stream Limits
transactional_recipient_limit_exceeded and marketing_recipient_limit_exceeded are 400, not 429: see the Request Validation section above. BATCH_NOT_ALLOWED_FOR_TRANSACTIONAL is also 400: a batch send is not allowed on a transactional credential regardless of rate limits.
Quota and Billing
| Code | Description |
|---|---|
QUOTA_EXCEEDED | Usage quota exceeded for the current billing period |
Policy Engine
| Code | Description |
|---|---|
SENDING_BLOCKED | The rate/warmup policy engine blocked this send: verification level, the sandbox allow list, account restriction, or an unusual volume spike |
MARKETING_PAUSED | Marketing emails are paused for this workspace |
Server Errors (5xx)
| Code | HTTP Status | Description |
|---|---|---|
INTERNAL_ERROR | 500 | Unexpected internal server error |
AUTHENTICATION_FAILED | 500 | API key validation failed internally (not a wrong login, retry) |
TIMEOUT | 504 | Operation timed out |
SERVICE_UNAVAILABLE | 503 | Service is temporarily unavailable |
DATABASE_ERROR | 503 | Database error occurred |
Server errors (5xx) are transient. Retry the request with exponential backoff. If the error persists, check the MailLand status page or contact support.
Handling Errors
Retry Strategy
| HTTP Status | Retry? | Strategy |
|---|---|---|
| 400 | No | Fix the request and try again |
| 401 | No | Check credentials or refresh your token |
| 403 | No | Verify permissions or upgrade your plan |
| 404 | No | Check the resource ID |
| 409 | No | Resolve the conflict |
| 422 | No | Fix the business logic issue (e.g. verify domain) |
| 429 | Yes | Wait for the Retry-After duration, then retry |
| 500 | Yes | Retry with exponential backoff (max 3 retries) |
| 503 | Yes | Retry with exponential backoff (max 5 retries) |
Reading Rate Limit Headers
Most responses include X-RateLimit-Limit and X-RateLimit-Remaining:
| Header | Description |
|---|---|
X-RateLimit-Limit | Maximum requests allowed in the current window |
X-RateLimit-Remaining | Requests remaining in the current window |
An IP-based 429 additionally adds:
| Header | Description |
|---|---|
X-RateLimit-Reset | ISO-8601 UTC timestamp when the current window resets (IP rate limit responses only) |
Retry-After | Seconds to wait before retrying |
Next Steps
- Rate Limits: detailed rate limit tiers and best practices
- Authentication: token and API key management
- Changelog: track API changes