メールチェックAPIリファレンス
POST/v1/email/validate
1件のメールアドレスをチェックします:構文、既知の使い捨て/一時的なドメイン、ドメインのメールサーバー(MX)、入力ミスの可能性、ロールアドレスを確認し、理由を添えてaccept/review/rejectの判定を返します。{ "email": "user@example.com" }というJSON本文を送信してください。GET /v1/geoと同じ、公開可能でオリジンロックされたキーのモデルを使い、サインアップフォーム自身のJavaScriptから呼び出されるように設計されています。多数のアドレスや、サーバーサイドでのサインアップ判断には、このページの後半にある一括チェック、リストジョブ、サインアップチェックの各エンドポイントを使用してください。すべてのチェックはドメインとアドレスのレベルで行われます。メールボックスには一切接続しないため、どの結果もメールボックスの存在、所有者、メールが届くことを証明するものではありません。
認証
POST /v1/email/validateは、X-Api-Keyヘッダーでオリジンロックされた公開可能キーを受け付けます — GET /v1/geoと同じキー種別と許可オリジンのモデルです。このページのその他すべてのエンドポイント(一括チェック、リストジョブ、サインアップチェック)は多数のアドレスや任意のIPを受け付けるため、Authorization: Bearerでシークレットキーが必要であり、必ずバックエンドから呼び出してください。公開可能キーを使うと403が返ります。
レスポンスフィールド
- 送信したアドレス。送信された内容そのままが返されます。
- domain
- 小文字化したドメイン(国際化ドメインはpunycode)。syntaxValidがfalseの場合はnull。
- syntaxValid
- アドレスが構文上有効かどうか。メールボックスの存在や配信可能性のチェックではありません。
- isDisposable
- ドメインが既知の使い捨て/一時的なメールプロバイダーに該当するかどうか — 直接、親ドメイン経由、または使い捨てドメインを扱うことが知られているメールサーバー経由で判定します。syntaxValidがfalseの場合は常にfalse。
- normalizedEmail
- 前後の空白を除去して小文字化し、ドメインをpunycodeにしたアドレス。syntaxValidがfalseの場合はnull。
- canonicalEmail
- normalizedEmailから+タグを除いたもの(Gmailの場合はさらにドットを除去し、googlemail.comをgmail.comに統一) — 同一人物による二重登録を見つけるために保存してください。syntaxValidがfalseの場合はnull。
- disposableSource
- isDisposableがtrueになった理由:list(ドメイン自体がリストに掲載)、parent_domain(親ドメインが掲載、例:a.b.mailinator.com)、mx_host(ドメインのメールサーバーが既知の使い捨てドメインを扱っている)。isDisposableがfalseの場合はnull。
- isFreeProvider
- ドメインがgmail.comやoutlook.comのような一般消費者向けメールボックスプロバイダーかどうか。参考情報であり、判定を変えることはありません。
- isRoleAccount
- ローカル部がadmin@、info@、noreply@のようなロールアドレスかどうか。
- didYouMean
- アドレス全体に対する入力ミスの修正候補(john@gmial.com → john@gmail.com)、またはnull。自前の正常なメールサーバーを持つドメインは、一般的なプロバイダーと1文字違いでない限り「修正」されません。
- mx.status
- found(MXレコードあり)、implicit(MXはないがA/AAAAレコードあり)、none(どちらもなし)、null_mx(ドメインがメールを受け付けないと宣言)、no_domain(ドメインが存在しない)、unknown(検索が失敗またはタイムアウト)のいずれか。syntaxValidがfalseの場合、mxオブジェクト全体がnullになります。
- mx.host
- statusがfoundの場合は優先度値が最も低いMXホスト、それ以外はnull。個々のメールボックスが存在するかどうかについては何も示しません。
- verdict
- accept、review、reject — reasonsに含まれる条件のうち最も重いもの。最終決定ではなく、自社ポリシーのための推奨です。
- reasons
- 該当したすべての条件(重いものから順)。verdictがacceptの場合は空です。下記の「判定と理由コード」を参照してください。
エラー
- 400
- 不正な形式のリクエスト本文。一括:empty_batchまたはbatch_too_large(100件超)。サインアップチェック:invalid_ip。リストジョブ:invalid_body、empty_job、job_too_large(100,000件超)。無効なメールアドレスは400にはならず、判定reject・理由invalid_syntaxの結果として返されます。
- 401
- APIキーが欠落しているか無効です。
- 403
- POST /v1/email/validate:リクエストのOrigin/Refererがキーの許可オリジンリストにない(CORSヘッダーが設定されないため、JSON本文に関係なくブラウザがレスポンスをブロックします)。シークレットキー用エンドポイント:公開可能キーが使われた。
- 404
- job_not_found — このIDのリストジョブがアカウントに存在しません。
- 409
- job_not_completed — ジョブがまだキュー待ちか処理中、または失敗しています。結果はジョブ完了後にのみダウンロードできます。
- 410
- job_expired — ジョブのアップロード済みアドレスと結果は削除済みです(作成から7日後)。
- 413
- body_too_large — 10 MBを超えるジョブのCSVアップロード。
- 415
- JSONでもtext/csvでもないリストジョブの本文。
- 429
- 1分あたりのレート制限、またはプランの月間リクエスト上限を超える場合のmonthly_limit_exceeded — 見分け方はエラーとレート制限を参照してください。上限を超える一括チェックやリストジョブは、処理を始める前に全体が拒否されます。
- 503
- job_storage_unavailable — リストジョブを保存できませんでした。課金は発生していません。再試行してください。
例
リクエスト
curl https://api.watch-ip.com/v1/email/validate \
-H "X-Api-Key: YOUR_PUBLISHABLE_KEY" \
-H "Content-Type: application/json" \
-d '{"email": "John.Doe+news@Gmial.com"}'レスポンス
{
"email": "John.Doe+news@Gmial.com",
"domain": "gmial.com",
"syntaxValid": true,
"isDisposable": false,
"normalizedEmail": "john.doe+news@gmial.com",
"canonicalEmail": "john.doe@gmial.com",
"disposableSource": null,
"isFreeProvider": false,
"isRoleAccount": false,
"didYouMean": "john.doe+news@gmail.com",
"mx": {
"status": "none",
"host": null
},
"verdict": "reject",
"reasons": [
"no_mail_server",
"typo_suspected"
]
}判定と理由コード
各条件は最低限の判定を定め、最も重いものが採用されます。reasonsには該当したすべてが重い順に列挙されます。フリーメールのアドレスを許容するかどうかはお客様の判断に委ねられ、判定を変えることはありません。
- invalid_syntax
- Reject。アドレスが構文上無効です(長さの上限、使用可能な文字、ドットの位置、IPリテラルではなく実在ドメインであること)。引用符付きのローカル部も拒否されます — 規格上は有効ですが、サインアップで使われることは事実上ありません。
- domain_not_found
- Reject。ドメインがDNSに存在しません。
- no_mail_server
- Reject。ドメインがメールを受け付けないと宣言している(「null MX」)か、MXレコードもA/AAAAレコードもありません。
- disposable_domain
- Reject。ドメイン、その親ドメイン、またはドメインのメールサーバーが既知の使い捨て/一時的なメールプロバイダーに該当します — disposableSourceを参照してください。
- typo_suspected
- Review。didYouMeanに修正候補(例:gmial.com → gmail.com)が入っています。
- role_account
- Review。ローカル部がadmin@、info@、support@、noreply@のようなロールアドレスで、通常は個人用ではなく共有されています。
- implicit_mx
- Review。ドメインにMXレコードがなく、メールはA/AAAAアドレスにフォールバックします。実際のメールドメインではまれな構成です。
- dns_unavailable
- Review。DNS検索が失敗またはタイムアウトしたため、ドメインのメール設定が不明です(mx.status: unknown)。アドレスに不利な証拠ではありません。
一括チェック
POST/v1/email/batch
1回のリクエストで1〜100件のアドレスを、POST /v1/email/validateと同じチェックと結果形式でチェックし、入力順にアドレスごとの結果を返します。{ "emails": [...] }を送信してください。同じドメインのアドレスは1回のDNS検索を共有します。アドレスごとに1リクエストとして月間プラン上限に計上され、上限を超える一括チェックは429 monthly_limit_exceededで全体が拒否されます。1分あたりのレート制限に対しては、呼び出し全体が1リクエストとして数えられます。シークレットキー専用。
リクエスト
curl https://api.watch-ip.com/v1/email/batch \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{"emails": ["user@gmail.com", "someone@mailinator.com"]}'レスポンス
{
"results": [
{ "email": "user@gmail.com", "verdict": "accept", "reasons": [], ... },
{ "email": "someone@mailinator.com", "isDisposable": true, "disposableSource": "list", "verdict": "reject", "reasons": ["disposable_domain"], ... }
]
}メールリストジョブ
POST/v1/email/jobs
最大100,000件のアドレスをバックグラウンドでチェックします。JSON { "emails": [...], "filename": "..." }、または最大10 MBのtext/csv本文を送信してください:見出しがemail(e-mail、email address、email_address、mailも可、大文字小文字は区別しない)の列が使われ、該当する見出しがなければ先頭列が使われます。区切り文字はカンマ、セミコロン、タブを自動検出します。ジョブは作成時に課金されます — 重複を除いたアドレス(完全一致)ごとに1リクエストなので、重複もチェックされますが課金は1回です — 月間上限を超えるリストは全体が拒否されます。再試行後もジョブの一部を処理できなかった場合、ジョブはfailedとなり、未処理分のクレジットは返還されます。ジョブオブジェクトとともに202を返します。シークレットキー専用。同じジョブはダッシュボードのEmail listsページからもアップロード・ダウンロードできます。
リクエスト
curl https://api.watch-ip.com/v1/email/jobs \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Content-Type: text/csv" \
--data-binary @newsletter.csvレスポンス
{
"id": "5b0d6f5e-8a51-4f7e-9d0e-2c1f3f7f8a11",
"status": "queued",
"source": "api",
"filename": null,
"total": 12840,
"credits": 12512,
"processed": 0,
"summary": null,
"createdAt": "2026-09-28T10:00:00.000Z",
"completedAt": null,
"expiresAt": "2026-10-05T10:00:00.000Z"
}ジョブのステータス
GET/v1/email/jobs/{id}
同じジョブオブジェクトを返します。statusがcompletedになるまでポーリングしてください。ポーリングは課金されません。
- status
- queued → processing → completed。failed:再試行後もリストの一部を処理できませんでした。結果はなく、未処理分のクレジットは返還済みです。expired:アップロード済みアドレスと結果は作成から7日後に削除されました。
- total
- 送信された行数(重複を含む)。
- credits
- 課金されたリクエスト数:重複を除いたアドレスごとに1件。
- processed
- これまでにチェックされた行数。
- summary
- 完了後:判定(accept/review/reject)ごと、および発生した理由コードごとの行数。それまではnull。
- expiresAt
- アップロード済みアドレスと結果が削除される日時。
ジョブの結果
GET/v1/email/jobs/{id}/results
送信された各行に対して1行ずつ、送信順(重複を含む)のCSVをダウンロードします。列:email、normalized_email、verdict、reasons、syntax_valid、is_disposable、disposable_source、is_free_provider、is_role_account、did_you_mean、mx_status、mx_host。reasonsはセミコロン区切り、空のセルはnullを意味し、構文上無効なアドレスではmx_statusは空です(検索を行っていないため)。=、+、-、@で始まる無効なアドレスには、表計算ソフトが数式として実行しないようにアポストロフィが先頭に付けられます。ジョブ完了までは409、期限切れ後は410。ダウンロードは課金されません。
リクエスト
curl https://api.watch-ip.com/v1/email/jobs/5b0d6f5e-8a51-4f7e-9d0e-2c1f3f7f8a11/results \
-H "Authorization: Bearer YOUR_SECRET_KEY" -o results.csvサインアップチェック
POST/v1/signup/check
サインアップフォームの送信時にバックエンドから、メールアドレスとIPに基づいてサインアップを1回の呼び出しでスコアリングします(ブラウザで計算した判定は偽装される可能性があります)。{ "email": "...", "ip": "...", "userAgent": "..." }を送信してください — userAgentは任意です。レスポンスには、メールチェックの完全な結果(email)、IPの国とASN、およびセキュリティデータを含むプランではVPN/Tor/データセンター/脅威の指標(ip)、公開登録データ(RDAP)に基づくメールドメインの経過日数(emailDomainAgeDays。不明な場合と著名な一般消費者向けプロバイダーではnull)、0〜100のスコア(下記の理由ごとの重みの合計、上限100)、および判定(60以上はreject、25以上はreview、それ以外はaccept)が含まれます。セキュリティデータのないプランでは、ip.securityはnullとなり、スコアはメールのシグナルのみを使い、reasonsにip_security_unavailableが含まれます。1リクエストとして計上されます。シークレットキー専用。
- invalid_syntax
- 70
- domain_not_found · no_mail_server · disposable_domain
- 各60
- ip_tor · ip_threat
- 各40
- ip_vpn
- 25
- new_domain
- 25 — メールドメインの登録から30日未満
- ip_datacenter
- 20 — IPがVPNやTorの出口でない場合のみ
- automated_user_agent
- 20 — 指定されたuserAgentがボットやスクリプトのように見える
- typo_suspected
- 15
- role_account · implicit_mx
- 各10
- dns_unavailable
- 5
- ip_security_unavailable
- 0 — 参考情報:このプランにはセキュリティデータがありません
リクエスト
curl https://api.watch-ip.com/v1/signup/check \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{"email": "jane@new-startup.io", "ip": "203.0.113.1"}'レスポンス
{
"email": { "email": "jane@new-startup.io", "verdict": "accept", "reasons": [], ... },
"ip": {
"ip": "203.0.113.1",
"country": "US",
"asn": 64500,
"asOrganization": "Example Hosting",
"security": { "isTor": false, "isVpn": false, "isDatacenter": true, "isThreat": false, "isSanctionedNetwork": false }
},
"emailDomainAgeDays": 12,
"score": 45,
"verdict": "review",
"reasons": ["new_domain", "ip_datacenter"]
}制限
チェックしたアドレスはすべて、プラン共通の月間上限に対して1リクエストとして計上されます — 単一チェック、一括チェックの各アドレス、リストジョブの重複を除いた各アドレス — サインアップチェックは1リクエストです。一括チェックとリストジョブは全体が受け付けられるか拒否されるかのいずれかで、部分的に処理されることはありません。1分あたりのレート制限はアイテム数ではなくHTTP呼び出し数で数えます。最大100件のIPまたはメールアドレスを含むバッチは1リクエストとして数えられ、各アイテムは引き続き月間リクエスト上限に個別に計上されます。リストジョブのアップロードと結果はジョブ作成から7日後に削除されます。DNS検索には短い時間枠があり、失敗やタイムアウトの場合はエラーではなく、mx.status unknownと理由dns_unavailableに縮退します。使い捨てドメインのデータは、コミュニティが管理する3つのオープンソースリストを統合したもので、数時間ごとに更新され、掲載ドメインを扱っていることが観測されたメールサーバーで拡張されます — データソースを参照してください。非常に新しい使い捨てプロバイダーは、まだ検出されない場合があります。すべてのチェックはドメインとアドレスのレベルで行われます。メールボックスには一切接続しないため、どの結果もメールボックスの存在、所有者、メールが届くことを証明するものではありません。