Handling email API errors and limits: status codes, retries and monitoring

What each Inbixio API response means, which errors to retry and which to fix, how monthly limits work, and how to monitor delivery in production.

Sending one email in a demo is easy. Sending a hundred thousand a month in production means planning for the moments things go wrong: a revoked key, an expired card, a month that ends sooner than expected, a mail server having a bad day.

This guide explains every response the Inbixio send endpoint returns, what your code should do about each one, and how to watch delivery once you are live.

Two stages: accepted, then delivered

A call to POST /api/send-email/ happens in two stages:

  1. The API request. Inbixio checks your key, its permissions, your subscription, your monthly usage and the request body. If everything is in order it returns 200 and queues the message.
  2. Delivery. A moment later Inbixio connects to your SMTP server and hands the message over. Each message is recorded as sent or failed, and those results feed the figures on your dashboard.

So a 200 means “accepted for delivery”, not “in the inbox”. Problems at stage 1 come back as HTTP errors your code can handle. Problems at stage 2, such as a wrong SMTP password, show up in the dashboard’s failed-delivery rate. Inbixio makes one delivery attempt per message; it doesn’t retry a failed delivery.

Every response, and what to do

Status Body Meaning What your code should do
200 {"message": "Email queued successfully."} Accepted Done
400 {"error": "to_email, subject, and message are required."} A field is missing or empty Fix the request; don’t retry
400 {"error": "to_email must be a single valid email address."} Not exactly one valid address Fix the request; don’t retry
400 {"error": "subject must be a single line of at most 500 characters."} Subject too long or has a line break Fix the request; don’t retry
400 {"error": "message must be text of at most 1,000,000 characters."} Body too large Fix the request; don’t retry
400 {"error": "No SMTP configuration found. Please add an email server first."} No server connected Add a server in the dashboard
401 {"detail": "API key missing"} No X-API-Key header Fix the configuration; don’t retry
401 {"detail": "Invalid API key"} Wrong, renewed or deleted key Update the key; alert your team
401 {"detail": "API key access not allowed"} The key has been disabled Use another key; alert your team
402 {"error": "An active subscription is required to send emails."} Subscription inactive Fix billing; alert your team
403 {"error": "This API key does not have send permission."} Key lacks Send Enable Send or use another key
429 {"error": "Monthly email limit reached for your plan.", "limit": 25000, "sent": 25000} Plan limit reached Upgrade, or hold mail until the next month; don’t retry
429 {"detail": "Request was throttled. Expected available in 12 seconds."} Too many requests with this key in a short time (rate limit) Wait for the Retry-After header, then retry
503 {"error": "Too many emails are waiting to be sent. Please retry in a few seconds."} Temporarily busy Wait for the Retry-After header, then retry
5xx / timeout — Temporary problem Retry with backoff

Error messages arrive under error for most responses and under detail for authentication errors, so read both:

const body = await res.json().catch(() => ({}));
const reason = body.error ?? body.detail ?? res.statusText;

Retry only what can succeed later

Retrying a 401 a hundred times won’t make the key valid; it just fills your logs. Split errors into two groups:

  • Retry: network errors, timeouts, 5xx responses and the rate-limit 429 (the one with a detail message). Wait as long as the Retry-After header says, otherwise use exponential backoff with jitter, and give up after a few attempts.
  • Don’t retry: 400, 401, 402, 403 and the monthly-limit 429 (the one with limit and sent). These need a human or a different request. Log them loudly, and alert on 401, 402 and the monthly-limit 429 because they stop all your email.
// 5xx and the short-term rate limit can succeed later; the monthly limit (body has `limit`) can't.
const retryable = (status, body) => status >= 500 || (status === 429 && body.limit === undefined);

export async function sendWithRetry(payload, attempts = 4) {
  for (let i = 0; i < attempts; i++) {
    let res;
    try {
      res = await fetch('https://backend.inbixio.com/api/send-email/', {
        method: 'POST',
        headers: { 'X-API-Key': process.env.INBIXIO_API_KEY, 'Content-Type': 'application/json' },
        body: JSON.stringify(payload),
        signal: AbortSignal.timeout(15_000),
      });
    } catch (err) {
      if (i === attempts - 1) throw err; // network error or timeout: retry
    }
    if (res?.ok) return res.json();
    if (res) {
      const body = await res.json().catch(() => ({}));
      if (!retryable(res.status, body)) {
        throw new Error(`Inbixio ${res.status}: ${body.error ?? body.detail ?? res.statusText}`);
      }
    }
    const retryAfter = Number(res?.headers.get('Retry-After')) * 1000;
    const delay = retryAfter || Math.min(30_000, 1000 * 2 ** i) * (0.5 + Math.random()); // 0.5s–30s with jitter
    await new Promise((r) => setTimeout(r, delay));
  }
  throw new Error('Inbixio: gave up after retries');
}

About duplicates: if a request times out, it may still have been accepted. Retrying could then send the same email twice. For receipts and notifications that’s usually acceptable; for anything where a duplicate would confuse users, record what you sent in your own database and check before retrying.

Monthly limits

Each plan includes a number of emails per month: 25,000 on Starter and 150,000 on Growth. Inbixio counts successfully sent emails in the current calendar month. When you reach the limit, sends return 429 with your limit and current sent count, until the next month starts or you upgrade.

Don’t wait for the 429:

  • The API Keys page shows a Usage Limit card with this month’s sent count against your plan limit.
  • Set yourself a reminder to check it at around 80% of your limit, and plan an upgrade before a big launch or import.
  • For a step-by-step volume estimate, see choosing an email API plan.

Delivery failures (stage 2)

When the API accepted a message but your SMTP server refused it, it counts as a failed delivery. The dashboard shows the Failed Deliveries rate for the last 7 days rather than a list of individual messages, so watch the rate and check your server settings when it rises. The usual causes:

  • Authentication failed: the mailbox password changed, or the provider now requires an app password.
  • Connection problems: the host or port in your server settings is wrong.
  • Provider limits: your mail provider capped the mailbox’s daily sending.
  • Rejected recipient: your server refused the address during sending. Bounces that arrive later as emails go to the sending mailbox, not to Inbixio, so check that inbox too.

The fix almost always lives in Email Servers or with your mail provider. SMTP settings explained covers the common cases.

What to monitor in production

Your Inbixio dashboard gives you the essentials:

  • Email Sent and the Failed Deliveries rate for the last 7 days, each with the change against the 7 days before.
  • Avg Latency: how long your SMTP server takes to accept mail. A sudden jump often comes before failures.
  • API and email volume charts across the year, to spot trends and seasonal peaks.
  • Logs of every API call: event ID, endpoint, method, status code, response time and timestamp.

On your side, track the number of non-200 responses by status code and alert when 401, 402 or the monthly-limit 429 appear. Those mean all email has stopped, and your users will notice before your logs do.

Checklist

  • Treat 200 as “queued”; check delivery results on the dashboard
  • Read both error and detail from error responses
  • Retry only network errors, timeouts, 5xx, 503 and the rate-limit 429, honouring Retry-After
  • Alert on 401, 402 and the monthly-limit 429
  • Keep an eye on the Usage Limit card before launches and imports
  • Watch the Failed Deliveries rate and fix SMTP settings promptly

Send it with Inbixio

Connect your own SMTP server, create a scoped API key and send from any language with one HTTPS request.

Create account See pricing