Typeform
Email checker for Typeform. Verify emails in Typeform responses and integrations.
Typeform に EmailVerify を統合し、回答が送信されたときにメールアドレスを検証して、高品質なリードと有効な連絡先情報を確保しましょう。
連携方法
| 方法 | 最適な用途 | 複雑さ |
|---|---|---|
| Webhook | リアルタイム検証 | 低 |
| Zapier | ノーコード自動化 | 低 |
| API 連携 | カスタムワークフロー | 中 |
方法 1:Webhook 連携
フォーム回答が送信されたときにメールを検証する Webhook をセットアップします。
Webhook エンドポイントの作成
// pages/api/typeform/webhook.js
import crypto from 'crypto';
import EmailVerify from '@emailverify/sdk';
const bv = new EmailVerify(process.env.EMAILVERIFY_API_KEY);
export default async function handler(req, res) {
if (req.method !== 'POST') {
return res.status(405).json({ error: 'Method not allowed' });
}
// Typeform の署名を検証
const signature = req.headers['typeform-signature'];
if (!verifySignature(req.body, signature)) {
return res.status(401).json({ error: 'Invalid signature' });
}
const { form_response } = req.body;
// 回答からメールを抽出
const email = extractEmail(form_response.answers);
if (!email) {
return res.status(200).json({ message: 'No email found' });
}
// メールを検証
const result = await bv.verify({ email });
// 結果に基づいて処理
await processVerification(form_response, email, result);
res.status(200).json({ success: true });
}
function verifySignature(payload, signature) {
const secret = process.env.TYPEFORM_WEBHOOK_SECRET;
const hash = crypto
.createHmac('sha256', secret)
.update(JSON.stringify(payload))
.digest('base64');
return `sha256=${hash}` === signature;
}
function extractEmail(answers) {
const emailAnswer = answers.find(
answer => answer.type === 'email'
);
return emailAnswer?.email || null;
}
async function processVerification(response, email, result) {
const responseId = response.token;
// 検証結果を保存
await storeResult(responseId, {
email,
status: result.status,
score: result.score,
disposable: result.is_disposable,
verified_at: new Date().toISOString(),
});
// 結果に基づいてアクション
if (result.status === 'invalid' || result.is_disposable) {
// フラグまたは通知
await sendNotification({
type: 'invalid_email',
response_id: responseId,
email,
reason: result.status === 'invalid'
? '無効なメールアドレス'
: '使い捨てメールを検出',
});
} else if (result.status === 'valid') {
// CRM やメールリストに追加
await addToCRM(email, response);
}
}Typeform で Webhook を設定
- Typeform でフォームを開く
- Connect → Webhooks をクリック
- Add a webhook をクリック
- Webhook URL を入力:
https://yoursite.com/api/typeform/webhook - シークレットをコピーして環境変数に追加
方法 2:Zapier 連携
ノーコード自動化のために Zapier を使用して Typeform を EmailVerify に接続します。
Zap の設定
- トリガー:Typeform → New Entry
- アクション:Webhooks by Zapier → POST
Webhook の設定
URL: https://api.emailverify.ai/v1/verify
Method: POST
Headers:
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json
Data:
{
"email": "{{email_field}}",
"webhook_url": "https://hooks.zapier.com/hooks/catch/xxx/yyy"
}結果の処理
検証結果を処理する 2 番目の Zap を追加:
- トリガー:Webhooks by Zapier → Catch Hook
- フィルター:status = "invalid" または disposable = true の場合のみ続行
- アクション:Gmail → Send Email(チームに通知)または Google Sheets → Create Row(ログ)
方法 3:API 連携
両方の API を使用してカスタム連携を構築します。
Typeform 回答ハンドラー
// services/typeform-verification.ts
import EmailVerify from '@emailverify/sdk';
interface TypeformAnswer {
type: string;
email?: string;
text?: string;
field: {
id: string;
ref: string;
type: string;
};
}
interface TypeformResponse {
token: string;
submitted_at: string;
answers: TypeformAnswer[];
}
interface VerificationResult {
responseId: string;
email: string;
status: string;
score: number;
isValid: boolean;
isDisposable: boolean;
}
class TypeformVerificationService {
private bv: EmailVerify;
constructor() {
this.bv = new EmailVerify(process.env.EMAILVERIFY_API_KEY!);
}
async verifyResponse(response: TypeformResponse): Promise<VerificationResult | null> {
const email = this.extractEmail(response.answers);
if (!email) {
return null;
}
const result = await this.bv.verify({ email });
return {
responseId: response.token,
email,
status: result.status,
score: result.score,
isValid: result.status === 'valid' && !result.is_disposable,
isDisposable: result.is_disposable,
};
}
private extractEmail(answers: TypeformAnswer[]): string | null {
const emailAnswer = answers.find(a => a.type === 'email');
return emailAnswer?.email || null;
}
async verifyBulkResponses(responses: TypeformResponse[]): Promise<VerificationResult[]> {
const emails = responses
.map(r => this.extractEmail(r.answers))
.filter((email): email is string => email !== null);
if (emails.length === 0) {
return [];
}
// 一括検証を使用
const job = await this.bv.verifyBulk(emails);
// 完了を待機
let status;
do {
await this.sleep(5000);
status = await this.bv.getBulkJobStatus(job.job_id);
} while (status.status !== 'completed');
const results = await this.bv.getBulkJobResults(job.job_id);
// 結果を回答にマッピング
return responses
.map(response => {
const email = this.extractEmail(response.answers);
if (!email) return null;
const result = results.results.find(r => r.email === email);
if (!result) return null;
return {
responseId: response.token,
email,
status: result.status,
score: result.score,
isValid: result.status === 'valid' && !result.is_disposable,
isDisposable: result.is_disposable,
};
})
.filter((r): r is VerificationResult => r !== null);
}
private sleep(ms: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, ms));
}
}
export const typeformVerification = new TypeformVerificationService();使用例
import { typeformAPI } from './services/typeform-api';
import { typeformVerification } from './services/typeform-verification';
// 最近の回答を検証
async function verifyRecentResponses(formId: string) {
const yesterday = new Date();
yesterday.setDate(yesterday.getDate() - 1);
const { items } = await typeformAPI.getResponses(formId, {
since: yesterday.toISOString(),
page_size: 100,
});
console.log(`${items.length} 件の回答を検証中...`);
const results = await typeformVerification.verifyBulkResponses(items);
// レポートを生成
const valid = results.filter(r => r.isValid).length;
const invalid = results.filter(r => !r.isValid).length;
console.log(`結果: ${valid} 件有効、${invalid} 件無効`);
// 無効な回答をフラグ
for (const result of results) {
if (!result.isValid) {
await flagInvalidResponse(result);
}
}
return results;
}
async function flagInvalidResponse(result: VerificationResult) {
// フラグリストに追加、通知を送信など
console.log(`回答をフラグ ${result.responseId}: ${result.email}`);
}リアルタイムフォーム検証
Typeform はネイティブでカスタム検証をサポートしていませんが、埋め込み Typeform を使用したランディングページで対応できます。
事前検証ランディングページ
<!DOCTYPE html>
<html>
<head>
<title>お問い合わせフォーム</title>
<style>
.form-container {
max-width: 500px;
margin: 50px auto;
padding: 20px;
}
.pre-check {
margin-bottom: 20px;
}
.pre-check input {
width: 100%;
padding: 12px;
font-size: 16px;
border: 1px solid #ddd;
border-radius: 4px;
}
.pre-check .status {
margin-top: 8px;
font-size: 14px;
}
.pre-check .status.valid { color: #28a745; }
.pre-check .status.invalid { color: #dc3545; }
.pre-check .status.checking { color: #666; }
.typeform-container {
display: none;
}
.typeform-container.visible {
display: block;
}
</style>
</head>
<body>
<div class="form-container">
<div class="pre-check">
<label>まず、メールアドレスを確認させてください:</label>
<input type="email" id="email" placeholder="your@email.com" />
<div class="status" id="status"></div>
</div>
<div class="typeform-container" id="typeform">
<div data-tf-widget="FORM_ID" data-tf-hidden="email="></div>
</div>
</div>
<script src="//embed.typeform.com/next/embed.js"></script>
<script>
const emailInput = document.getElementById('email');
const statusEl = document.getElementById('status');
const typeformContainer = document.getElementById('typeform');
let verifiedEmail = null;
emailInput.addEventListener('blur', async function() {
const email = this.value;
if (!email || !email.includes('@')) {
return;
}
statusEl.textContent = 'メールを確認中...';
statusEl.className = 'status checking';
try {
const response = await fetch('/api/verify-email', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email }),
});
const result = await response.json();
if (result.valid) {
statusEl.textContent = '✓ メール確認済み!下のフォームに進んでください。';
statusEl.className = 'status valid';
verifiedEmail = email;
// 事前入力されたメールで Typeform を表示
showTypeform(email);
} else {
statusEl.textContent = '✗ ' + (result.message || '有効なメールを入力してください');
statusEl.className = 'status invalid';
}
} catch (error) {
// エラー時は許可
statusEl.textContent = '';
showTypeform(email);
}
});
function showTypeform(email) {
typeformContainer.classList.add('visible');
// 隠しフィールドを更新
const widget = typeformContainer.querySelector('[data-tf-widget]');
widget.setAttribute('data-tf-hidden', `email=${encodeURIComponent(email)}`);
// Typeform 埋め込みを再初期化
window.tf.createWidget();
}
</script>
</body>
</html>ベストプラクティス
1. 常に Webhook 署名を検証
function verifySignature(payload, signature) {
const secret = process.env.TYPEFORM_WEBHOOK_SECRET;
const hash = crypto
.createHmac('sha256', secret)
.update(JSON.stringify(payload))
.digest('base64');
return `sha256=${hash}` === signature;
}2. API エラーを適切に処理
try {
const result = await bv.verify({ email });
// 結果を処理
} catch (error) {
console.error('検証に失敗:', error);
// API エラー時は送信を拒否しない
await processWithoutVerification(response);
}3. 事前検証済みメールには隠しフィールドを使用
事前検証ページを使用する場合、検証済みメールを隠しフィールドとして渡す:
data-tf-hidden="email={{verified_email}}"