Jotform Email Verification
Email checker for Jotform. Verify emails in Jotform submissions and workflows.
Интегрируйте EmailVerify с JotForm для верификации email-адресов в реальном времени и обеспечения высокого качества отправок форм.
Методы интеграции
| Метод | Лучше для | Сложность |
|---|---|---|
| Вебхук | Серверная верификация | Низкая |
| Виджет | Валидация в реальном времени | Средняя |
| Zapier | Автоматизация без кода | Низкая |
Метод 1: Интеграция через вебхук
Настройте вебхук для верификации email при отправке форм.
Настройка вебхука JotForm
- Откройте вашу форму в JotForm
- Перейдите в Settings → Integrations
- Найдите WebHooks
- Добавьте URL вашего вебхука:
https://yoursite.com/api/jotform/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 sends data as form-urlencoded
const { rawRequest, formID, submissionID } = req.body;
// Parse the raw request
const formData = JSON.parse(rawRequest || '{}');
// Find email field
const email = findEmailField(formData);
if (!email) {
return res.status(200).json({ message: 'No email field found' });
}
// Verify email
const result = await bv.verify({ email });
// Process result
await processVerification({
formId: formID,
submissionId: submissionID,
email,
verification: result,
});
res.status(200).json({ success: true });
}
function findEmailField(formData) {
// JotForm field names are like q3_email, q5_yourEmail, etc.
for (const [key, value] of Object.entries(formData)) {
if (typeof value === 'string' && value.includes('@')) {
// Basic email pattern check
if (/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) {
return value;
}
}
}
return null;
}
async function processVerification({ formId, submissionId, email, verification }) {
// Store result in your database
await storeResult({
formId,
submissionId,
email,
status: verification.status,
score: verification.score,
isDisposable: verification.is_disposable,
verifiedAt: new Date().toISOString(),
});
// Handle invalid emails
if (verification.status === 'invalid' || verification.is_disposable) {
await handleInvalidEmail({
formId,
submissionId,
email,
reason: verification.status === 'invalid'
? 'Invalid email address'
: 'Disposable email detected',
});
}
}
async function handleInvalidEmail({ formId, submissionId, email, reason }) {
// Option 1: Send notification
await sendNotification({
type: 'invalid_email',
formId,
submissionId,
email,
reason,
});
// Option 2: Update JotForm submission (mark as spam)
await updateSubmission(submissionId, {
flag: 'spam',
note: `Email verification failed: ${reason}`,
});
}Обновление отправки JotForm
Используйте API JotForm для маркировки или обновления отправок:
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 для валидации email в реальном времени.
Код виджета
<!-- widget.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Email Verification Widget</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="Enter your email"
/>
<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();
}
}
};
// Configuration from widget settings
var widgetConfig = {};
JFCustomWidget.subscribe('ready', function() {
// Get widget settings
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', 'Please enter a valid email format');
return;
}
clearTimeout(verifyTimeout);
verifyTimeout = setTimeout(function() {
verifyEmail(email);
}, 300);
});
function verifyEmail(email) {
showStatus('verifying', '<span class="loader"></span> Verifying...');
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', '✓ Email verified');
isValid = true;
} else if (result.status === 'invalid') {
showStatus('invalid', '✗ Please enter a valid email');
isValid = false;
} else if (result.disposable && widgetConfig.blockDisposable) {
showStatus('invalid', '✗ Please use a permanent email');
isValid = false;
} else {
showStatus('valid', '✓ Email verified');
isValid = true;
}
// Send value to JotForm
JFCustomWidget.sendData({
value: email,
valid: isValid
});
})
.catch(function(error) {
console.error('Verification error:', error);
// Allow on 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 перейдите в Form Builder → Add Form Element → Widgets
- Найдите ваш виджет или используйте "Custom HTML"
- Настройте URL виджета
Метод 3: Интеграция через Zapier
Подключите JotForm к EmailVerify через Zapier.
Настройка Zap
Шаг 1: Триггер
- Приложение: JotForm
- Событие: New Submission
Шаг 2: Верификация email
- Приложение: 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: Действие (для невалидных email)
- Приложение: Gmail
- Событие: Send Email
- Конфигурация:
To: admin@yourcompany.com Subject: Invalid Email Submission - JotForm Body: Email {{email}} failed verification. Status: {{status}}
API-интеграция JotForm
Для продвинутых рабочих процессов используйте API JotForm напрямую.
Получение и верификация отправок
// 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,
});
// Update submission with verification result
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;
}
// Also check text fields that might contain email
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();
}
async addSubmissionNote(submissionId, note) {
// JotForm doesn't have a direct note API, but you can update custom fields
// or use a separate tracking system
}
}
export const jotformService = new JotFormService();Использование
import { jotformService } from './services/jotform';
// Verify all submissions for a form
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('Verification Results:', stats);
return results;
}Интеграция условной логики
Используйте результаты верификации для управления поведением формы.
Валидация перед отправкой
// Embed this in your form page
<script>
document.addEventListener('DOMContentLoaded', function() {
const form = document.querySelector('form[id^="form_"]');
const emailField = document.querySelector('input[type="email"]');
let emailVerified = false;
let verificationResult = null;
// Verify on blur
emailField.addEventListener('blur', async function() {
const email = this.value;
if (!email) return;
try {
const response = await fetch('/api/verify-email', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email }),
});
verificationResult = await response.json();
emailVerified = verificationResult.status === 'valid' &&
!verificationResult.disposable;
updateFieldUI(emailField, verificationResult);
} catch (error) {
// Allow on error
emailVerified = true;
}
});
// Validate on submit
form.addEventListener('submit', function(e) {
if (!emailVerified) {
e.preventDefault();
alert('Please enter a valid email address to continue.');
emailField.focus();
return false;
}
});
function updateFieldUI(field, result) {
// Remove existing classes
field.classList.remove('valid', 'invalid');
// Find or create status element
let statusEl = field.parentNode.querySelector('.email-status');
if (!statusEl) {
statusEl = document.createElement('span');
statusEl.className = 'email-status';
field.parentNode.appendChild(statusEl);
}
if (result.status === 'valid' && !result.disposable) {
field.classList.add('valid');
statusEl.textContent = '✓ Email verified';
statusEl.style.color = '#28a745';
} else {
field.classList.add('invalid');
statusEl.textContent = result.disposable
? '✗ Please use a permanent email'
: '✗ Please enter a valid email';
statusEl.style.color = '#dc3545';
}
}
});
</script>Массовая верификация существующих данных
Обработка исторических отправок:
async function bulkVerifyJotFormData(formId) {
console.log('Starting bulk verification...');
// Get all submissions
const allSubmissions = [];
let offset = 0;
const limit = 100;
while (true) {
const submissions = await jotformService.getFormSubmissions(formId, {
limit,
offset,
});
if (submissions.length === 0) break;
allSubmissions.push(...submissions);
offset += limit;
console.log(`Fetched ${allSubmissions.length} submissions...`);
}
console.log(`Total submissions: ${allSubmissions.length}`);
// Extract emails
const emailMap = new Map();
for (const submission of allSubmissions) {
const email = jotformService.findEmailInSubmission(submission);
if (email) {
emailMap.set(submission.id, email);
}
}
console.log(`Found ${emailMap.size} emails to verify`);
// Bulk verify
const emails = [...emailMap.values()];
const job = await bv.verifyBulk(emails);
console.log(`Job ID: ${job.job_id}`);
// Wait for completion
let status;
do {
await sleep(5000);
status = await bv.getBulkJobStatus(job.job_id);
console.log(`Progress: ${status.progress_percent}%`);
} while (status.status !== 'completed');
// Get results
const results = await bv.getBulkJobResults(job.job_id);
// Process results
const stats = { valid: 0, invalid: 0, disposable: 0 };
for (const result of results.results) {
if (result.status === 'valid') stats.valid++;
else stats.invalid++;
if (result.is_disposable) stats.disposable++;
// Find and flag invalid submissions
if (result.status === 'invalid' || result.is_disposable) {
for (const [submissionId, email] of emailMap.entries()) {
if (email === result.email) {
await jotformService.flagSubmission(submissionId);
break;
}
}
}
}
console.log('Verification complete:', stats);
return stats;
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}Лучшие практики
1. Корректно обрабатывайте ошибки API
try {
const result = await verifyEmail(email);
// Process result
} catch (error) {
console.error('Verification failed:', error);
// Don't block submission on API errors
return { valid: true };
}2. Кэшируйте результаты
const cache = new Map();
const CACHE_TTL = 24 * 60 * 60 * 1000; // 24 hours
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. Ограничение частоты для вебхуков
const rateLimiter = new Map();
function checkRateLimit(ip, limit = 10, windowMs = 60000) {
const now = Date.now();
const requests = rateLimiter.get(ip) || [];
// Remove old requests
const recent = requests.filter(time => now - time < windowMs);
if (recent.length >= limit) {
return false;
}
recent.push(now);
rateLimiter.set(ip, recent);
return true;
}