Jotform
Email checker for Jotform. Verify emails in Jotform submissions and workflows.
JotForm に EmailVerify を統合し、リアルタイムでメールアドレスを検証して高品質なフォーム送信を確保しましょう。
連携方法
| 方法 | 最適な用途 | 複雑さ |
|---|---|---|
| Webhook | サーバーサイド検証 | 低 |
| ウィジェット | リアルタイム検証 | 中 |
| Zapier | ノーコード自動化 | 低 |
方法 1:Webhook 連携
フォーム送信時にメールを検証する Webhook をセットアップします。
JotForm Webhook の設定
- JotForm でフォームを開く
- 設定 → 連携 に移動
- WebHooks を検索
- Webhook URL を追加:
https://yoursite.com/api/jotform/webhook
Webhook ハンドラー
// pages/api/jotform/webhook.js
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' });
}
// JotForm は form-urlencoded でデータを送信
const { rawRequest, formID, submissionID } = req.body;
// raw request をパース
const formData = JSON.parse(rawRequest || '{}');
// メールフィールドを見つける
const email = findEmailField(formData);
if (!email) {
return res.status(200).json({ message: 'No email field found' });
}
// メールを検証
const result = await bv.verify({ email });
// 結果を処理
await processVerification({
formId: formID,
submissionId: submissionID,
email,
verification: result,
});
res.status(200).json({ success: true });
}
function findEmailField(formData) {
// JotForm のフィールド名は q3_email、q5_yourEmail のような形式
for (const [key, value] of Object.entries(formData)) {
if (typeof value === 'string' && value.includes('@')) {
// 基本的なメールパターンチェック
if (/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) {
return value;
}
}
}
return null;
}
async function processVerification({ formId, submissionId, email, verification }) {
// データベースに結果を保存
await storeResult({
formId,
submissionId,
email,
status: verification.status,
score: verification.score,
isDisposable: verification.is_disposable,
verifiedAt: new Date().toISOString(),
});
// 無効なメールを処理
if (verification.status === 'invalid' || verification.is_disposable) {
await handleInvalidEmail({
formId,
submissionId,
email,
reason: verification.status === 'invalid'
? '無効なメールアドレス'
: '使い捨てメールを検出',
});
}
}
async function handleInvalidEmail({ formId, submissionId, email, reason }) {
// オプション 1:通知を送信
await sendNotification({
type: 'invalid_email',
formId,
submissionId,
email,
reason,
});
// オプション 2:JotForm 送信を更新(スパムとしてマーク)
await updateSubmission(submissionId, {
flag: 'spam',
note: `メール検証に失敗: ${reason}`,
});
}JotForm 送信の更新
JotForm API を使用して送信をマークまたは更新:
async function updateSubmission(submissionId, updates) {
const response = await fetch(
`https://api.jotform.com/submission/${submissionId}?apiKey=${process.env.JOTFORM_API_KEY}`,
{
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
'submission[flag]': updates.flag || '0',
'submission[new]': '0',
}),
}
);
return response.json();
}方法 2:カスタムウィジェット
リアルタイムメール検証用のカスタム JotForm ウィジェットを作成します。
ウィジェットコード
<!-- widget.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>メール検証ウィジェット</title>
<link href="https://cdn.jotfor.ms/stylebuilder/static/form-common.css" rel="stylesheet">
<style>
.widget-container {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
}
.email-input {
width: 100%;
padding: 10px;
font-size: 14px;
border: 1px solid #ccc;
border-radius: 4px;
box-sizing: border-box;
}
.email-input:focus {
outline: none;
border-color: #4a90d9;
}
.email-input.valid {
border-color: #28a745;
}
.email-input.invalid {
border-color: #dc3545;
}
.status-message {
margin-top: 5px;
font-size: 12px;
}
.status-message.verifying {
color: #666;
}
.status-message.valid {
color: #28a745;
}
.status-message.invalid {
color: #dc3545;
}
.loader {
display: inline-block;
width: 12px;
height: 12px;
border: 2px solid #ccc;
border-top-color: #666;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
</style>
</head>
<body>
<div class="widget-container">
<input
type="email"
id="email"
class="email-input"
placeholder="メールアドレスを入力"
/>
<div id="status" class="status-message"></div>
</div>
<script src="https://cdn.jotfor.ms/static/prototype.forms.js"></script>
<script src="https://cdn.jotfor.ms/static/jotform.forms.js"></script>
<script>
var JFCustomWidget = {
subscribe: function(event, callback) {
if (event === 'ready') {
callback();
}
}
};
// ウィジェット設定からの構成
var widgetConfig = {};
JFCustomWidget.subscribe('ready', function() {
// ウィジェット設定を取得
var settings = JFCustomWidget.getWidgetSettings();
widgetConfig.apiEndpoint = settings.apiEndpoint || '/api/verify-email';
widgetConfig.blockDisposable = settings.blockDisposable !== 'false';
initWidget();
});
function initWidget() {
var emailInput = document.getElementById('email');
var statusEl = document.getElementById('status');
var verifyTimeout;
var isValid = false;
emailInput.addEventListener('blur', function() {
var email = this.value.trim();
if (!email) {
clearStatus();
return;
}
if (!isValidFormat(email)) {
showStatus('invalid', '有効なメール形式を入力してください');
return;
}
clearTimeout(verifyTimeout);
verifyTimeout = setTimeout(function() {
verifyEmail(email);
}, 300);
});
function verifyEmail(email) {
showStatus('verifying', '<span class="loader"></span> 確認中...');
fetch(widgetConfig.apiEndpoint, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email: email })
})
.then(function(response) { return response.json(); })
.then(function(result) {
if (result.status === 'valid' && !result.disposable) {
showStatus('valid', '✓ メール確認済み');
isValid = true;
} else if (result.status === 'invalid') {
showStatus('invalid', '✗ 有効なメールを入力してください');
isValid = false;
} else if (result.disposable && widgetConfig.blockDisposable) {
showStatus('invalid', '✗ 恒久的なメールを使用してください');
isValid = false;
} else {
showStatus('valid', '✓ メール確認済み');
isValid = true;
}
// JotForm に値を送信
JFCustomWidget.sendData({
value: email,
valid: isValid
});
})
.catch(function(error) {
console.error('検証エラー:', error);
// エラー時は許可
isValid = true;
clearStatus();
JFCustomWidget.sendData({ value: email, valid: true });
});
}
function showStatus(type, message) {
statusEl.innerHTML = message;
statusEl.className = 'status-message ' + type;
emailInput.className = 'email-input ' + (type === 'verifying' ? '' : type);
}
function clearStatus() {
statusEl.innerHTML = '';
statusEl.className = 'status-message';
emailInput.className = 'email-input';
}
function isValidFormat(email) {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
}
}
</script>
</body>
</html>ウィジェットのホストと登録
- ウィジェット HTML をサーバーにホスト
- JotForm で フォームビルダー → フォーム要素を追加 → ウィジェット に移動
- ウィジェットを検索または「Custom HTML」を使用
- ウィジェット URL を設定
方法 3:Zapier 連携
Zapier を使用して JotForm を EmailVerify に接続します。
Zap のセットアップ
ステップ 1:トリガー
- アプリ:JotForm
- イベント:New Submission
ステップ 2:メールを検証
- アプリ:Webhooks by Zapier
- イベント:POST
- 設定:
URL: https://api.emailverify.ai/v1/verify Headers: Authorization: Bearer YOUR_API_KEY Content-Type: application/json Data: {"email": "{{email_field}}"}
ステップ 3:フィルター
- 続行条件:
{{status}}がvalidと等しくない
ステップ 4:アクション(無効なメールの場合)
- アプリ:Gmail
- イベント:Send Email
- 設定:
To: admin@yourcompany.com Subject: 無効なメール送信 - JotForm Body: メール {{email}} の検証に失敗しました。ステータス: {{status}}
JotForm API 連携
高度なワークフローには JotForm API を直接使用します。
送信の取得と検証
// services/jotform.js
import EmailVerify from '@emailverify/sdk';
const bv = new EmailVerify(process.env.EMAILVERIFY_API_KEY);
const jotformApiKey = process.env.JOTFORM_API_KEY;
class JotFormService {
async getFormSubmissions(formId, options = {}) {
const params = new URLSearchParams({
apiKey: jotformApiKey,
limit: options.limit || 100,
offset: options.offset || 0,
filter: JSON.stringify(options.filter || {}),
});
const response = await fetch(
`https://api.jotform.com/form/${formId}/submissions?${params}`
);
const data = await response.json();
return data.content;
}
async verifySubmissions(formId) {
const submissions = await this.getFormSubmissions(formId, {
filter: { 'status:ne': 'DELETED' }
});
const results = [];
for (const submission of submissions) {
const email = this.findEmailInSubmission(submission);
if (!email) continue;
const verification = await bv.verify({ email });
results.push({
submissionId: submission.id,
email,
status: verification.status,
score: verification.score,
isDisposable: verification.is_disposable,
});
// 無効な送信をフラグ
if (verification.status === 'invalid' || verification.is_disposable) {
await this.flagSubmission(submission.id);
}
}
return results;
}
findEmailInSubmission(submission) {
const answers = submission.answers || {};
for (const [questionId, answer] of Object.entries(answers)) {
if (answer.type === 'control_email') {
return answer.answer;
}
// メールを含む可能性のあるテキストフィールドもチェック
if (answer.answer && typeof answer.answer === 'string') {
if (/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(answer.answer)) {
return answer.answer;
}
}
}
return null;
}
async flagSubmission(submissionId) {
const response = await fetch(
`https://api.jotform.com/submission/${submissionId}?apiKey=${jotformApiKey}`,
{
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
'submission[flag]': '1',
}),
}
);
return response.json();
}
}
export const jotformService = new JotFormService();使用例
import { jotformService } from './services/jotform';
// フォームのすべての送信を検証
async function verifyFormSubmissions(formId) {
const results = await jotformService.verifySubmissions(formId);
const stats = {
total: results.length,
valid: results.filter(r => r.status === 'valid' && !r.isDisposable).length,
invalid: results.filter(r => r.status === 'invalid').length,
disposable: results.filter(r => r.isDisposable).length,
};
console.log('検証結果:', stats);
return results;
}ベストプラクティス
1. API エラーを適切に処理
try {
const result = await verifyEmail(email);
// 結果を処理
} catch (error) {
console.error('検証に失敗:', error);
// API エラー時は送信をブロックしない
return { valid: true };
}2. 結果をキャッシュ
const cache = new Map();
const CACHE_TTL = 24 * 60 * 60 * 1000; // 24 時間
async function verifyWithCache(email) {
const cached = cache.get(email);
if (cached && Date.now() - cached.timestamp < CACHE_TTL) {
return cached.result;
}
const result = await bv.verify({ email });
cache.set(email, { result, timestamp: Date.now() });
return result;
}3. Webhook のレート制限
const rateLimiter = new Map();
function checkRateLimit(ip, limit = 10, windowMs = 60000) {
const now = Date.now();
const requests = rateLimiter.get(ip) || [];
// 古いリクエストを削除
const recent = requests.filter(time => now - time < windowMs);
if (recent.length >= limit) {
return false;
}
recent.push(now);
rateLimiter.set(ip, recent);
return true;
}