APIリファレンス
POST /api/v1/sendが、トランザクション送信APIのすべてです — バージョン管理された、安定した1つのエンドポイントです。MailInAppの他のルート(呼び出し元は常に自分たちのフロントエンドだけで、自由に変更できます)とは異なり、これは第三者のコードが依存するコントラクトであるため、初日からバージョン管理されています。
認証
Authorization: Bearer mia_live_...
キーが欠落しているか無効な場合は401が返されます。キーはダッシュボードの開発者で管理されます — クイックスタートを参照してください。取り消したキーは即座に使えなくなります。
リクエスト
Content-Type: application/jsonです。このエンドポイントは2つのリクエスト形式を共有しており、どちらが適用されるかはprojectIdが存在するかどうかで決まります。
自由形式
| フィールド | 型 | 必須 | 注記 |
| --- | --- | --- | --- |
| to | string | 必須 | 単一の受信者アドレスです。 |
| subject | string | 必須 | 200文字に切り詰められます。 |
| html | string | 必須 | そのまま送信されます — レンダリング、マージタグ、スタジオのパイプラインは一切適用されません。 |
| text | string | 必須 | プレーンテキストのパートです。 |
テンプレート
| フィールド | 型 | 必須 | 注記 |
| --- | --- | --- | --- |
| to | string | 必須 | 単一の受信者アドレスです。 |
| projectId | string | 必須 | 自分が所有するプロジェクトである必要があります — スタジオURLは/studio/<projectId>です。 |
| mergeData | object | 任意 | 最大100フィールドまでのフラットな{ key: value }オブジェクトです。データソースの行の代わりとなり、プロジェクトの{{field}}マージタグへ解決されます。ネストしたオブジェクト/配列は破棄され、null/undefinedは空文字列になり、それ以外はすべて文字列化されます。 |
| subject | string | 任意 | 省略した場合はプロジェクトの名前が既定値になります。件名内のマージタグはmergeDataから解決されます。200文字に切り詰められます。 |
どちらの形式にも一致しないボディ(例:toが欠落している、またはhtml/textとprojectIdの両方が欠落している)には400が返されます。
共通フィールド
| フィールド | 型 | 必須 | 注記 |
| --- | --- | --- | --- |
| type | "transactional" | "marketing" | 任意 | 既定値は"transactional"です。下記を参照してください。 |
| from | object | 任意 | 送信者のアドレス/名前を1回の呼び出しだけ上書きします — { "email": string, "name"?: string }。下記を参照してください。 |
| senderId | string | 任意 | fromをインラインで指定する代わりに、アカウントに保存済みの送信者アイデンティティの1つを選んで、1回の呼び出しだけ上書きします。自分のアカウントに属するものである必要があり、そうでない場合は400です。両方指定された場合はfromが優先されます。 |
| replyTo | string | 任意 | 1回の呼び出しだけのReply-Toアドレスです。下記を参照してください。 |
ヘッダー
| ヘッダー | 必須 | 注記 |
| --- | --- | --- |
| Authorization | 必須 | Bearer <apiKey>。 |
| Idempotency-Key | 任意 | 冪等性を参照してください。 |
レスポンス
{ "id": "abc123", "status": "sent" }
statusは次のいずれかです:
| ステータス | 意味 |
| --- | --- |
| sent | 送信方法(SMTPリレーまたはネイティブ送信)へ正常に引き渡されました。 |
| suppressed | 受信者がサプレッションリストに含まれています — トランザクションとマーケティングを参照してください。メールは送信されていませんが、これはエラーではありません。 |
| failed | 送信の試行が失敗しました(例:SMTPリレーが未設定、またはメッセージを拒否した)。errorフィールドに、人間が読める理由が入ります。 |
エラーコード
| ステータス | 意味 |
| --- | --- |
| 400 | 不正なJSON、自由形式にもテンプレート形式にも一致しないリクエスト、無効なtype、無効または許可されていないfrom(From addressを参照)、無効なreplyTo、または(テンプレートモードで)存在しないか自分のものではないprojectIdです。アカウントに有効な送信方法が設定されていない場合にも返されます。 |
| 401 | Authorizationヘッダーが欠落もしくは無効、またはキーが取り消されています。 |
| 404 | (テンプレートモード)プロジェクトが存在しない、またはあなたのアカウントが所有していません — 他のアカウントにとってどのプロジェクトIDが有効かを漏らさないよう、意図的に「存在しない」場合と同じレスポンスにしています。 |
| 429 | レート制限を超えています — レート制限を参照してください。 |
リクエスト自体は有効だったが、実際の送信の試行が後段で失敗した場合には、(2xx以外のステータスではなく)status: "failed"を伴う200が返されます。「リクエストを拒否した」のか「試したが送信できなかった」のかを区別する必要がある場合は、HTTPステータスコードだけでなく、ボディ内のstatusを確認してください。
トランザクションとマーケティング
typeフィールドは、どのサプレッションリストをチェックするかを制御します。これは、ESPがトランザクションとマーケティングのストリームを分離する方法を反映しています:
type: "transactional"(既定値) — 配信停止によるサプレッションを回避します。パスワードリセットや注文レシートは、受信者がニュースレターの配信を停止したというだけの理由でブロックされるべきではありません。バウンスによるサプレッションは絶対に回避しません — 意図に関係なく、死んだアドレスは死んだままです。type: "marketing"— ダッシュボードからのキャンペーン送信と全く同じように動作します:配信停止・バウンスの両方によるサプレッションでブロックされます。
どちらの場合も、ブロックされたときはエラーではなくstatus: "suppressed"が返されます。
Fromアドレス
既定では、すべての送信はアカウントに設定された送信者アイデンティティを使用します — ネイティブ(SES)送信の場合は設定 → ドメインの「From address」カード、それ以外の場合は自分のSMTPリレーに設定されたfromアドレスです。1回の呼び出しだけ上書きするにはfromを渡します:
{
"to": "[email protected]",
"subject": "Your one-time code",
"html": "<p>Your code is 123456</p>",
"text": "Your code is 123456",
"from": { "email": "[email protected]", "name": "FitConsent Sales Team" }
}
fromが指定されている場合、from.emailは常に必須です — 名前だけの上書きはできないため、ここに指定した値は、その呼び出しにおいてアドレスと表示名の両方を常に完全に置き換えます。from.nameは任意です。省略すると、素のアドレスだけで送信されます。
アカウントが認証済みドメインを通じて送信している場合(ネイティブ/SES送信)、from.emailは自分自身の認証済み送信ドメインのいずれかのアドレスである必要があります(例:[email protected]は可、[email protected]は不可)— アカウントは複数のドメインを認証できるため、そのいずれも許可されますが、他人のドメインは絶対に許可されません。ネイティブ送信は、すべてのMailInApp顧客で共有される1つのプラットフォームAWSアカウント上で実行されるため、この制限が、あるアカウントが別のアカウントの認証済みドメインから届いたように見えるメールを送信することを防いでいます。SMTP送信にはこのような制限はありません:送信は自分自身のリレー/認証情報を経由するため、そのリレー自身の送信者検証ルールによって、すでに信頼されているのと同じことになります。
senderId(上記の共通フィールドの表を参照)は、ダッシュボードで送信者アイデンティティをすでに設定している場合、通常はより簡単な選択肢です。呼び出しごとに繰り返し指定する必要なく、そのアイデンティティ自身の{email, name, reply-to}に解決されます。
無効または許可されていないfromは、送信を試みる前に400を返します。
Reply-Toアドレス
既定では、返信は送信方法に応じて設定の送信またはドメインページで設定したアカウントの既定のReply-Toに送られます。何も設定していない場合はどこにも送られません。1回の呼び出しだけ上書きするにはreplyToを渡します — 表示されるfromがno-replyアドレスでも、人間に返信を見てもらいたい場合に便利です:
{
"to": "[email protected]",
"subject": "Your order shipped",
"html": "<p>Your order is on its way.</p>",
"text": "Your order is on its way.",
"from": { "email": "[email protected]", "name": "FitConsent" },
"replyTo": "[email protected]"
}
from.emailとは異なり、replyToにはネイティブ(SES)送信でのドメイン制限がありません — 送信者アイデンティティや配信レピュテーションに影響することは一切なく、受信者のメールクライアントが返信を押したときに使うヘッダーにすぎません。無効なreplyToは、送信を試みる前に400を返します。
冪等性
再試行される可能性のある呼び出し(チェックアウトWebhookの再配信、メッセージを再処理するキューコンシューマーなど)にはIdempotency-Keyヘッダーを渡してください。同じアカウントに対して同じキーで再試行された呼び出しは、最初の呼び出しがまだ処理中であっても、2件目のメールを送信することなく、最初の呼び出しの{id, status}を返します。
キーはアカウントごとに区別され、有効期限はありません。すでに別のペイロードに使ったキーを再利用してしまわないようにするのは自分の責任です(その場合も新しいペイロードは送信されず、最初の呼び出しの結果が返されます)。キーを渡さない場合、すべての呼び出しが送信されます。
レート制限
3つの独立した上限が適用されます:
- APIキーごと: 1分あたりのリクエスト数の上限です。超えると、そのキーに対してのみ
429が返されます — 同じアカウントの他のキーには影響しません。 - アカウントごと、送信APIクォータ: プランには、1カレンダー月あたりの送信API呼び出し回数が含まれます(Freeでは月500回)。超えると、1日にクォータがリセットされるまで
429が返されます。 - アカウントごと、送信量: プランの月間累積送信量の上限で、すべての送信経路(ダッシュボードからの送信、スケジュール送信、ライフサイクルメール、このAPI)で共有されます。これは、アカウントの他の送信を保護しているのと同じ上限です — 送信APIに別枠の予算はありません。
テンプレートモードの詳細
テンプレートモードの送信は、紐付けられたプロジェクトを、通常の受信者送信と全く同じようにレンダリングします:フォールバックエンジンの3つのティア、インタラクティブブロック、そして保存された連絡先の行ではなくmergeDataから構築された、個人向けの署名付きライブビューリンクです。それ以降の挙動は、スタジオ主導の送信と全く同じです:
- 投票、評価、フォーム送信、開封は記録され、連絡先の行ではなくこの特定のAPI呼び出しに帰属付けられたうえで、プロジェクトの回答ビューに表示されます。
- プロジェクトのWebhookは、他のどの受信者とも同様に、インタラクションイベントごとに発火します。
- 最近の呼び出し(ステータス、受信者、タイムスタンプ)は、監査証跡としてダッシュボードの開発者ページに一覧表示されます。
ダッシュボード送信と1点だけ異なるのは、そのインタラクションの裏に保存されたデータソースの行が存在しないことです。そのため、自分側での結合は、行インデックスではなく回答の受信者識別子をキーにするべきです。