HubSpotフォームは、コンタクトを獲得するための仕組みです。送信されるたびに、コンタクトレコードが作成または更新され、プロパティが設定され、そのコンタクトをワークフローに登録することもできます。ただし、入力されたアドレスが実在するかどうかは教えてくれません。HubSpotのメールアドレス欄は形式をチェックし、@とドメインがあることを確認します。しかし、メールボックスが存在しない、使い捨てである、gmail.comの入力ミスであるといった点は見抜けません。このガイドでは、Qualisendを使ってHubSpotフォームのメールアドレスを検証する、実用的な2つの方法を紹介します。1つ目は、新しいアドレスをQualisend APIにPOSTするOperations Hubのワークフローによるリアルタイム検証です。2つ目は、コンタクトをCSVにエクスポートする一括検証です。どちらもネイティブコネクターは不要です(現時点では提供されていません)。HubSpot標準のワークフローアクションまたはエクスポートボタンだけで実現できます。
結論:2つの方法#
回答が必要なタイミングに合う方法を選びます。
- リアルタイム:新しくフォームを送信した人を、ワークフローに登録します。custom-codeまたはwebhookアクションがメールアドレスを付けてQualisend APIを呼び出します。続いて分岐で、判定をコンタクトプロパティに書き込みます。さらに、返された
statusに基づいて、レコードを振り分けるか除外します。 - 一括:コンタクトをCSVにエクスポートし、Qualisendの一括検証にかけます。次の送信の前に、配信不能なアドレスを除外します。
HubSpotのフォーム欄でメールボックスを確認できない理由#
HubSpotのemailフィールドが検証するのは形式です。フォームの送信を許可する前に、その文字列がアドレスの形をしているかどうかを確認します。これは正規表現と同じ種類のチェックで、失敗する理由も同じです。形式は到達性を保証しません。jane@gmial.comは形式チェックを通過します。throwaway@mailinator.comも通過します。昨年閉鎖したドメインにある、一見本物らしいアドレスも通過します。
これらは、送信するまで見つかりません。送信した時点では、存在しないアドレスはハードバウンスとなり、バウンス率と送信者レピュテーションを少しずつ損ないます。本格的な検証では、HubSpotにはないレイヤーが加わります。DNS/MXのルックアップとSMTPによるメールボックスの確認に加え、使い捨て、役割アドレス、キャッチオールのフラグです。この仕組みに慣れていない場合は、メールアドレス検証が実際に確認することが入門になります。
HubSpotフォームのメールアドレスを検証する2つの方法#
最初に重要な制約があります。標準のHubSpotフォームは、送信の途中で不正なメールアドレスをブロックできません。 「Submit」をクリックしてからレコードが作成されるまでの間に、外部APIを呼び出すサポートされた方法はありません。そのため、リアルタイム検証は、送信の直後にワークフローの中で行われ、インラインのゲートにはなりません。この制約が、以下の2つの方法の前提です。
| 方法 | 実行のタイミング | 適した用途 |
|---|---|---|
| リアルタイムのワークフロー | 各送信の数秒後 | リアルタイムの受付:最初の送信の前に、タグ付け、振り分け、フォローアップの保留を行う |
| CSVの一括検証 | 必要なときに、まとめて | 既存のコンタクトの積み残しと、定期的なリストの整備 |
方法1:Operations Hubのワークフローによるリアルタイム検証#
コンタクトベースのワークフローを作成し、登録トリガーを「Form submission」に設定して、対象のフォームに絞り込みます。新しくフォームを送信した人は、すべてこのワークフローに流れ込み、そこで検証の呼び出しと結果に応じた処理を行います。
呼び出しの方法は2つあります。ポータルと技術スタックに合うほうを選んでください。
オプションA:custom-codeアクション(自己完結型)。 Operations Hub ProfessionalまたはEnterpriseを利用している場合、custom-codeアクションで、ワークフローの内部でそのままNode.js(またはPython)を実行できます。登録されたコンタクトのemailを入力プロパティとして追加し、キーをQUALISEND_API_KEYという名前のシークレットとして保存して、アクションからQualisendを呼び出します。
// HubSpot custom-code action (Node.js) — input property: email, secret: QUALISEND_API_KEY
const QUALISEND_ENDPOINT = "https://app.qualisend.com/api/v1/verify"; // confirm the path in /developers
exports.main = async (event, callback) => {
const email = event.inputFields.email;
// Fail open — never block a real lead on a transient API error.
const failOpen = () => callback({ outputFields: { email_status: "unknown" } });
let res;
try {
res = await fetch(QUALISEND_ENDPOINT, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.QUALISEND_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ email }),
signal: AbortSignal.timeout(10000),
});
} catch {
return failOpen(); // timeout or network error
}
if (!res.ok) return failOpen(); // 402 out of credits, 429 rate limited, 5xx
const { job_id, result } = await res.json();
callback({
outputFields: {
email_status: result.status, // deliverable / risky / undeliverable / unknown
email_score: result.score,
email_smtp: result.smtp, // pending / cached / skipped
qualisend_job_id: job_id,
},
});
};
このアクションは、出力としてemail_status、email_score、email_smtp、qualisend_job_idを公開します。email_smtpがcachedまたはskippedの場合、判定はすでに最終結果です。pendingの場合は、メールボックスの確認がまだ実行中で、email_statusは暫定のローカル判定にすぎません(通常はunknown)。そのため、まだこれで振り分けないでください。email_smtpで分岐し、短いDelayを入れてから、完了したジョブを読み取る2つ目のcustom-codeアクションを置きます。このアクションの入力はqualisend_job_idです。
// Second custom-code action, after the Delay: input qualisend_job_id, secret: QUALISEND_API_KEY
exports.main = async (event, callback) => {
const jobId = event.inputFields.qualisend_job_id;
try {
const res = await fetch(`https://app.qualisend.com/api/v1/jobs/${jobId}?include=results`, {
headers: { Authorization: `Bearer ${process.env.QUALISEND_API_KEY}` },
signal: AbortSignal.timeout(10000),
});
const job = res.ok ? await res.json() : null;
const row = job?.status === "completed" ? job.results?.[0] : null;
if (row) {
return callback({ outputFields: { email_status: row.status, email_score: row.score } });
}
} catch {
// timeout or network error: fall through and fail open
}
// Still running, or the API didn't answer: keep it unknown and re-check later.
callback({ outputFields: { email_status: "unknown" } });
};
どちらの分岐でも、最後のアクションの後にCopy property valueのステップを置き、email_statusをカスタムのコンタクトプロパティに書き込みます。続いてif/then branchでその値に基づいて振り分けます。これこそが、チェックを実行する目的です。
オプションB:自前の関数に送るwebhookアクション。 ロジックを自社のコードベースに置きたい場合や、custom-codeが使えないプランの場合は、自分で管理する小さなサーバーレス関数にPOSTするwebhookアクションを追加します。この関数がメールアドレスを取り出し、Qualisendを呼び出して、最終的な判定をHubSpotのCRM APIでコンタクトに書き戻します(smtpがpendingで返ってきた場合は、ジョブの完了後にGET /jobs/{job_id}からその判定を読み取ります)。サーバー側で動かす構成は、サインアップ時に検証するパターンと同じです。APIキーはサーバーの外に出ず、結果に基づいて処理します。Node.jsの解説やPythonの解説のエンドポイントコードは、ほぼそのまま使えます。HubSpot固有なのは、ペイロードの解析だけです。
どちらの場合も、基本のリクエストは同じです。プレースホルダーは、開発者向けドキュメントを見て自分の値に置き換えてください。
POST https://app.qualisend.com/api/v1/verify
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json
{ "email": "jane@example.com" }
配信可能なアドレスは、次のように返ってきます。status、0~100のscore、reason、sub_flagsのセットです。
{
"job_id": "6f1d2c3e-8a4b-4c5d-9e6f-7a8b9c0d1e2f",
"result": {
"status": "deliverable",
"score": 95,
"smtp": "cached",
"reason": "accepted_email",
"sub_flags": { "disposable": false, "role": false, "free_mail": false, "catch_all": false }
}
}
ここではsmtpがcachedなので、判定はすでに最終結果です。代わりにpendingの場合は、reasonはまだnullで、最終的なstatus、score、reasonはジョブの照会から取得します。
堅牢に保つためのルールが2つあります。専用のキーを使います。 このワークフロー専用に発行します(デフォルトのverifyスコープで、チェックとジョブの照会の両方に対応できます)。ログなどから漏えいしても、他に影響を与えずに無効化できます。そしてフェイルオープンにします。 Qualisendがタイムアウトした場合やプランの上限に達した場合は、そのアドレスをunknownとして扱い、一時的なエラーで本物のリードを失わないよう、コンタクトを残します。上のcatchと!res.okの分岐が、まさにそれを行っています。
下流では、判定は分岐にすぎません。出力から、カスタムの「Email status」プロパティを設定し、その後の処理をワークフローに決めさせます。deliverableのコンタクトは、そのままナーチャリングのシーケンスに進みます。undeliverableや使い捨てのコンタクトは、フォローアップを保留する、確認用にフラグを付ける、またはマーケティング対象外に設定して、アクティブなリストや送信から除外します。ワークフローは仕組みにすぎず、振り分けのルールは自分で決めます。
方法2:CSVエクスポートを一括検証する#
すでに数千件のコンタクトがある場合や、送信ごとのチェックよりスケジュールに沿ってクリーニングしたい場合は、まとめて処理します。この方法はワークフローが不要なので、Operations Hubの下位プランでも使えます。HubSpotでContactsを開き、リストまたはフィルターを選んで、CSVにExportします。コンタクト1件につき1行で、メールアドレスは専用の列に入ります。
その後の手順は次のとおりです。
- CSVをアップロードします。 Qualisendの一括検証にアップロードし、全行に対して、MX、SMTP、使い捨て、役割アドレス、キャッチオールの各フラグを含む全工程を実行させます。
- 注釈付きのファイルをダウンロードします。 各アドレスに、
status、reason、0~100のscoreが付いて返ってきます。 - HubSpotで配信不能なアドレスを除外します。 結果をインポートして「Email status」プロパティを設定し、配信可能でないものを、アクティブなリストとマーケティングの送信から除外します。
一括検証は積み残しの処理に適したツールですが、予防ではなく後始末です。ここで見つかるアドレスは、たいていすでにデータベースに残っています。定期的な一括検証とリアルタイムのワークフローを組み合わせれば、新しく届いた不正なアドレスを、届いた時点でフラグ付けできます。
判定結果への対応#
どちらの方法で結果が返ってきても、形は同じです。status、reason、score、サブフラグです。それぞれに、次のような対応を割り当てます。
| 結果 | HubSpotでの対応 |
|---|---|
deliverable | 受け付けます。ワークフローを続行し、通常どおり送信します。 |
undeliverable | 除外します。コンタクトをマーケティング対象外に設定するか、送信から除外します。reasonを見れば、ドメインが不正なのか、メールボックスが存在しないのかがわかります。 |
disposableフラグ | ファネルの厳しさに応じて、拒否またはタグ付けをします。詳しくは役割アドレス、使い捨て、フリーメールをご覧ください。 |
risky / キャッチオール | 受け付けますが、セグメントを分けます。キャッチオールドメインでは個別のメールボックスを確認できないため、慎重に送信します。 |
unknown | 受け付けて、あとで再チェックします。インフラから応答がなかっただけなので、これを理由に本物のリードを捨てないでください。 |
HubSpotのワークフローを使う方法と、自社のバックエンドから直接APIを呼び出す方法を比べる場合、どんな連携にも共通するトレードオフがあります。ワークフローは設定の速さで優れ、直接連携は大規模なときのコストと制御で優れています。同じwebhookのパターンは、ZapierやTypeformの姉妹ガイドでも使われています。HubSpotの外にも受付窓口がある場合に参考になります。
よくある質問
01HubSpot向けのQualisendネイティブ連携はありますか?
現時点ではありません。Qualisendのネイティブなプラットフォーム連携は作り直しの最中で、HubSpot Marketplaceにインストールできる専用アプリはまだありません。今後の予定に入っています。提供されるまでは、このガイドで説明しているとおり、ワークフローのcustom-codeまたはwebhookアクションからQualisend APIを呼び出す方法が、HubSpotフォームのメールアドレスを検証するための、サポートされた手段です。この方法のほうが柔軟でもあります。リクエスト、分岐、判定を書き込むコンタクトプロパティを、自分で管理できます。
02HubSpotフォームのメールアドレスを検証するには、Operations Hubが必要ですか?
リアルタイムのワークフローでは、事実上必要です。ワークフローにはProfessionalプランが必要で、特にwebhookとcustom-codeのアクションにはOperations Hub ProfessionalまたはEnterpriseが必要です。ポータルが下位のプランの場合は、代わりにCSVをエクスポートして一括検証する方法を使ってください。ワークフローもカスタムコードも不要で、エクスポートとファイルのアップロードだけで済むため、コンタクトをエクスポートできるプランであればどれでも使えます。
03フォームが送信される前に、不正なメールアドレスをブロックできますか?
確実にはできません。標準のHubSpotフォームには、送信の途中で外部APIを呼び出してレコードの作成を止める、サポートされた方法がありません。そのため、リアルタイム検証は送信の直後に、ワークフローの中で実行されます。実際には、それで問題ありません。数秒以内に検証して、アドレスにメッセージが届く前に対応できます。フォーム自体をブロックするのではなく、ウェルカムメールを保留する、コンタクトにタグを付ける、確認用に振り分けるといった対応を取ります。
04既存のHubSpotリストをクリーニングするのとは、どう違いますか?
受付時に検証すれば、新しい不正なアドレスの流入を防げます。既存のリストをクリーニングすれば、すでに入っているものを取り除けます。このガイドが扱うのは前者で、届いた送信を1件ずつチェックします。後者は、データベース全体を1回だけ(またはスケジュールに沿って)処理し、何を除外するか、古くなったコンタクトにどう再アプローチするかを決める作業です。各ステータスをどう扱うかを含む全体の手順は、メールリストをクリーニングする方法にあります。多くのチームが両方を行っています。
導入の準備はできましたか。開発者向けドキュメントで、スコープ付きのキーと正確なリクエスト形式を入手できます。無料メールチェッカーで1つのアドレスを確認することもできます。すべてのプランで使える100クレジットの無料枠で、有効にする前にワークフローを最初から最後まで試せます。



