メールAPIのエラーと上限への対処法:ステータスコード・リトライ・監視

Inbixio APIの各レスポンスの意味、リトライすべきエラーと修正すべきエラー、月間上限の仕組み、本番環境での配信状況の監視方法を解説します。

デモでメールを1通送るのは簡単です。しかし本番環境で月に10万通を送るなら、問題が起きる瞬間に備えておく必要があります。失効したキー、期限切れのカード、思ったより早く訪れる月末、調子の悪いメールサーバーなどです。

このガイドでは、Inbixioの送信エンドポイントが返すすべてのレスポンスと、それぞれに対してコードがすべきこと、そして運用開始後に配信状況を監視する方法を解説します。

2つの段階:受け付け、そして配信

POST /api/send-email/の呼び出しは、2つの段階で処理されます。

  1. APIリクエスト:Inbixioはキー、その権限、サブスクリプション、月間の利用量、リクエスト本文をチェックします。すべて問題なければ200を返し、メッセージをキューに追加します。
  2. 配信:その直後、Inbixioはお使いのSMTPサーバーに接続してメッセージを引き渡します。各メッセージは「送信済み」か「失敗」として記録され、その結果がダッシュボードの数値に反映されます。

つまり200は「配信のために受け付けた」という意味であり、「受信トレイに届いた」という意味ではありません。段階1の問題は、コードで処理できるHTTPエラーとして返ってきます。SMTPパスワードの誤りなど段階2の問題は、ダッシュボードの配信失敗率に表れます。Inbixioはメッセージごとに1回だけ配信を試み、失敗した配信をリトライすることはありません。

すべてのレスポンスと対応方法

ステータス 本文 意味 コードでの対応
200 {"message": "Email queued successfully."} 受け付け完了 完了
400 {"error": "to_email, subject, and message are required."} フィールドが欠けているか空 リクエストを修正。リトライしない
400 {"error": "to_email must be a single valid email address."} 有効なアドレスがちょうど1つではない リクエストを修正。リトライしない
400 {"error": "subject must be a single line of at most 500 characters."} 件名が長すぎるか改行を含む リクエストを修正。リトライしない
400 {"error": "message must be text of at most 1,000,000 characters."} 本文が大きすぎる リクエストを修正。リトライしない
400 {"error": "No SMTP configuration found. Please add an email server first."} サーバーが接続されていない ダッシュボードでサーバーを追加
401 {"detail": "API key missing"} X-API-Keyヘッダーがない 設定を修正。リトライしない
401 {"detail": "Invalid API key"} キーの誤り、更新済み、または削除済み キーを更新し、チームに通知
401 {"detail": "API key access not allowed"} キーが無効化されている 別のキーを使い、チームに通知
402 {"error": "An active subscription is required to send emails."} サブスクリプションが無効 請求情報を修正し、チームに通知
403 {"error": "This API key does not have send permission."} キーにSend権限がない Sendを有効にするか、別のキーを使う
429 {"error": "Monthly email limit reached for your plan.", "limit": 25000, "sent": 25000} プランの上限に到達 アップグレードするか、翌月まで送信を保留。リトライしない
429 {"detail": "Request was throttled. Expected available in 12 seconds."} 短時間にこのキーでのリクエストが多すぎる(レート制限) Retry-Afterヘッダーの時間だけ待ってからリトライ
503 {"error": "Too many emails are waiting to be sent. Please retry in a few seconds."} 一時的に混雑 Retry-Afterヘッダーの時間だけ待ってからリトライ
5xx / タイムアウト — 一時的な問題 バックオフしながらリトライ

エラーメッセージは、ほとんどのレスポンスではerrorに、認証エラーではdetailに入っているので、両方を読み取りましょう。

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

後で成功しうるものだけをリトライする

401を100回リトライしてもキーが有効になることはなく、ログが埋まるだけです。エラーは2つのグループに分けましょう。

  • リトライする:ネットワークエラー、タイムアウト、5xxレスポンス、そしてレート制限による429(detailメッセージを含むもの)。Retry-Afterヘッダーで指定された時間だけ待ち、ヘッダーがなければジッター付きの指数バックオフを使い、数回試して諦めます。
  • リトライしない:400、401、402、403、そして月間上限による429(limitとsentを含むもの)。これらは人の対応か、別のリクエストが必要です。目立つようにログに残し、401、402、月間上限の429についてはアラートを出しましょう。これらはすべてのメール送信を止めてしまうからです。
// 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');
}

重複について:リクエストがタイムアウトしても、実際には受け付けられている場合があります。その場合、リトライすると同じメールが2通送られる可能性があります。領収書や通知であれば通常は許容範囲ですが、重複がユーザーを混乱させるものについては、送信した内容を自社のデータベースに記録し、リトライ前に確認しましょう。

月間上限

各プランには月あたりの送信数が含まれています。Starterは25,000通、Growthは150,000通です。Inbixioは当月(暦月)に送信に成功したメールをカウントします。上限に達すると、翌月が始まるかアップグレードするまで、送信にはlimitと現在のsent数を含む429が返されます。

429が返ってくるまで待つ必要はありません。

  • API Keys(APIキー)ページにはUsage Limit(使用量の上限)カードがあり、今月の送信数とプランの上限が表示されます。
  • 上限の約80%に達したら確認するようリマインダーを設定し、大規模なローンチやインポートの前にはアップグレードを計画しましょう。
  • 送信数を段階的に見積もる方法は、メールAPIのプランの選び方をご覧ください。

配信の失敗(段階2)

APIがメッセージを受け付けたものの、お使いのSMTPサーバーが拒否した場合は、配信失敗としてカウントされます。ダッシュボードには個々のメッセージの一覧ではなく、過去7日間のFailed Deliveries(配信失敗)率が表示されるので、この割合を見守り、上昇したらサーバー設定を確認しましょう。主な原因は次のとおりです。

  • 認証の失敗:メールボックスのパスワードが変更された、またはプロバイダーがアプリパスワードを要求するようになった。
  • 接続の問題:サーバー設定のホストまたはポートが間違っている。
  • プロバイダーの制限:メールプロバイダーがメールボックスの1日あたりの送信数を制限した。
  • 受信者の拒否:送信中にサーバーがアドレスを拒否した。後からメールとして届くバウンスはInbixioではなく送信元のメールボックスに届くので、その受信トレイも確認しましょう。

修正箇所はほぼ必ず、Email Servers(メールサーバー)またはメールプロバイダー側にあります。よくあるケースはSMTP設定の解説で取り上げています。

本番環境で監視すべきこと

Inbixioのダッシュボードでは、必要な情報をひととおり確認できます。

  • 過去7日間のEmail Sent(送信済みメール)とFailed Deliveries率。それぞれ、その前の7日間との比較も表示されます。
  • Avg Latency(平均レイテンシ):SMTPサーバーがメールを受け付けるまでにかかる時間。急な上昇は、失敗の前兆であることがよくあります。
  • 1年間のAPIとメールの送信量グラフ:傾向や季節的なピークを把握できます。
  • すべてのAPI呼び出しのLogs(ログ):イベントID、エンドポイント、メソッド、ステータスコード、レスポンス時間、タイムスタンプ。

自社側では、200以外のレスポンスの件数をステータスコード別に記録し、401、402、月間上限の429が発生したらアラートを出しましょう。これらはすべてのメールが止まったことを意味し、ログより先にユーザーが気づいてしまいます。

チェックリスト

  • 200は「キューに追加済み」として扱い、配信結果はダッシュボードで確認する
  • エラーレスポンスからerrorとdetailの両方を読み取る
  • リトライするのはネットワークエラー、タイムアウト、5xx、503、レート制限の429だけにし、Retry-Afterに従う
  • 401、402、月間上限の429でアラートを出す
  • ローンチやインポートの前にUsage Limitカードを確認する
  • Failed Deliveries率を見守り、SMTP設定をすぐに修正する

Inbixioで送信しよう

お使いのSMTPサーバーを接続し、権限を絞ったAPIキーを作成すれば、HTTPSリクエスト1回であらゆる言語から送信できます。

アカウントを作成 料金を見る