EmailVerify LogoEmailVerify

Jotform Email Verification

Email checker for Jotform. Verify emails in Jotform submissions and workflows.

Интегрируйте EmailVerify с JotForm для верификации email-адресов в реальном времени и обеспечения высокого качества отправок форм.

Методы интеграции

МетодЛучше дляСложность
ВебхукСерверная верификацияНизкая
ВиджетВалидация в реальном времениСредняя
ZapierАвтоматизация без кодаНизкая

Метод 1: Интеграция через вебхук

Настройте вебхук для верификации email при отправке форм.

Настройка вебхука JotForm

  1. Откройте вашу форму в JotForm
  2. Перейдите в SettingsIntegrations
  3. Найдите WebHooks
  4. Добавьте 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>

Размещение и регистрация виджета

  1. Разместите HTML виджета на вашем сервере
  2. В JotForm перейдите в Form BuilderAdd Form ElementWidgets
  3. Найдите ваш виджет или используйте "Custom HTML"
  4. Настройте 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;
}

Связанные ресурсы

On this page