Jotform
Email checker for Jotform. Verify emails in Jotform submissions and workflows.
Integre EmailVerify con JotForm para verificar direcciones de correo electrónico en tiempo real y garantizar envíos de formularios de alta calidad.
Métodos de Integración
| Método | Mejor Para | Complejidad |
|---|---|---|
| Webhook | Verificación del lado del servidor | Baja |
| Widget | Validación en tiempo real | Media |
| Zapier | Automatización sin código | Baja |
Método 1: Integración por Webhook
Configure un webhook para verificar correos electrónicos cuando se envíen los formularios.
Configurar Webhook de JotForm
- Abra su formulario en JotForm
- Vaya a Configuración → Integraciones
- Busque WebHooks
- Agregue la URL de su webhook:
https://yoursite.com/api/jotform/webhook
Manejador del 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 envía datos como form-urlencoded
const { rawRequest, formID, submissionID } = req.body;
// Analizar la solicitud sin procesar
const formData = JSON.parse(rawRequest || '{}');
// Buscar campo de correo electrónico
const email = findEmailField(formData);
if (!email) {
return res.status(200).json({ message: 'No se encontró campo de correo electrónico' });
}
// Verificar correo electrónico
const result = await bv.verify({ email });
// Procesar resultado
await processVerification({
formId: formID,
submissionId: submissionID,
email,
verification: result,
});
res.status(200).json({ success: true });
}
function findEmailField(formData) {
// Los nombres de campo de JotForm son como q3_email, q5_yourEmail, etc.
for (const [key, value] of Object.entries(formData)) {
if (typeof value === 'string' && value.includes('@')) {
// Verificación básica de patrón de correo
if (/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) {
return value;
}
}
}
return null;
}
async function processVerification({ formId, submissionId, email, verification }) {
// Guardar resultado en su base de datos
await storeResult({
formId,
submissionId,
email,
status: verification.status,
score: verification.score,
isDisposable: verification.is_disposable,
verifiedAt: new Date().toISOString(),
});
// Manejar correos electrónicos inválidos
if (verification.status === 'invalid' || verification.is_disposable) {
await handleInvalidEmail({
formId,
submissionId,
email,
reason: verification.status === 'invalid'
? 'Dirección de correo electrónico inválida'
: 'Correo electrónico desechable detectado',
});
}
}
async function handleInvalidEmail({ formId, submissionId, email, reason }) {
// Opción 1: Enviar notificación
await sendNotification({
type: 'invalid_email',
formId,
submissionId,
email,
reason,
});
// Opción 2: Actualizar envío de JotForm (marcar como spam)
await updateSubmission(submissionId, {
flag: 'spam',
note: `Verificación de correo electrónico fallida: ${reason}`,
});
}Actualizar Envío de JotForm
Use la API de JotForm para marcar o actualizar envíos:
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();
}Método 2: Widget Personalizado
Cree un widget personalizado de JotForm para validación de correo electrónico en tiempo real.
Código del Widget
<!-- 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, Oxygin, 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;
}
// Enviar valor a JotForm
JFCustomWidget.sendData({
value: email,
valid: isValid
});
})
.catch(function(error) {
console.error('Error de verificación:', error);
// Permitir en caso de 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>Alojar y Registrar Widget
- Aloje el HTML del widget en su servidor
- En JotForm, vaya a Creador de Formularios → Agregar Elemento de Formulario → Widgets
- Busque su widget o use "HTML Personalizado"
- Configure la URL del widget
Método 3: Integración con Zapier
Conecte JotForm a EmailVerify usando Zapier.
Configuración del Zap
Paso 1: Disparador
- Aplicación: JotForm
- Evento: Nuevo Envío
Paso 2: Verificar Correo Electrónico
- Aplicación: Webhooks by Zapier
- Evento: POST
- Configuración:
URL: https://api.emailverify.ai/v1/verify Headers: Authorization: Bearer YOUR_API_KEY Content-Type: application/json Data: {"email": "{{email_field}}"}
Paso 3: Filtro
- Solo continuar si:
{{status}}no es igual avalid
Paso 4: Acción (para correos electrónicos inválidos)
- Aplicación: Gmail
- Evento: Enviar Correo Electrónico
- Configuración:
To: admin@yourcompany.com Subject: Envío de Correo Electrónico Inválido - JotForm Body: El correo electrónico {{email}} falló la verificación. Estado: {{status}}
Integración con la API de JotForm
Para flujos de trabajo avanzados, use la API de JotForm directamente.
Obtener y Verificar Envíos
// 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 no tiene una API de notas directa, pero puede actualizar campos personalizados
// o usar un sistema de seguimiento separado
}
}
export const jotformService = new JotFormService();Uso
import { jotformService } from './services/jotform';
// Verificar todos los envíos de un formulario
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('Resultados de Verificación:', stats);
return results;
}Integración de Lógica Condicional
Use los resultados de verificación para controlar el comportamiento del formulario.
Validación Previa al Envío
// Incruste esto en su página de formulario
<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;
// Verificar al perder el foco
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) {
// Permitir en caso de error
emailVerified = true;
}
});
// Validar al enviar
form.addEventListener('submit', function(e) {
if (!emailVerified) {
e.preventDefault();
alert('Por favor ingrese una dirección de correo electrónico válida para continuar.');
emailField.focus();
return false;
}
});
function updateFieldUI(field, result) {
// Eliminar clases existentes
field.classList.remove('valid', 'invalid');
// Encontrar o crear elemento de estado
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 = '✓ Correo electrónico verificado';
statusEl.style.color = '#28a745';
} else {
field.classList.add('invalid');
statusEl.textContent = result.disposable
? '✗ Por favor use un correo electrónico permanente'
: '✗ Por favor ingrese un correo electrónico válido';
statusEl.style.color = '#dc3545';
}
}
});
</script>Verificación en Lote para Datos Existentes
Procese envíos históricos:
async function bulkVerifyJotFormData(formId) {
console.log('Iniciando verificación en lote...');
// Obtener todos los envíos
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(`Obtenidos ${allSubmissions.length} envíos...`);
}
console.log(`Total de envíos: ${allSubmissions.length}`);
// Extraer correos electrónicos
const emailMap = new Map();
for (const submission of allSubmissions) {
const email = jotformService.findEmailInSubmission(submission);
if (email) {
emailMap.set(submission.id, email);
}
}
console.log(`Encontrados ${emailMap.size} correos electrónicos para verificar`);
// Verificación en lote
const emails = [...emailMap.values()];
const job = await bv.verifyBulk(emails);
console.log(`ID de Trabajo: ${job.job_id}`);
// Esperar finalización
let status;
do {
await sleep(5000);
status = await bv.getBulkJobStatus(job.job_id);
console.log(`Progreso: ${status.progress_percent}%`);
} while (status.status !== 'completed');
// Obtener resultados
const results = await bv.getBulkJobResults(job.job_id);
// Procesar resultados
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++;
// Encontrar y marcar envíos inválidos
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('Verificación completa:', stats);
return stats;
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}Mejores Prácticas
1. Manejar Errores de API con Gracia
try {
const result = await verifyEmail(email);
// Procesar resultado
} catch (error) {
console.error('Verificación fallida:', error);
// No bloquear el envío en caso de errores de API
return { valid: true };
}2. Almacenar Resultados en Caché
const cache = new Map();
const CACHE_TTL = 24 * 60 * 60 * 1000; // 24 horas
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. Limitación de Velocidad para Webhooks
const rateLimiter = new Map();
function checkRateLimit(ip, limit = 10, windowMs = 60000) {
const now = Date.now();
const requests = rateLimiter.get(ip) || [];
// Eliminar solicitudes antiguas
const recent = requests.filter(time => now - time < windowMs);
if (recent.length >= limit) {
return false;
}
recent.push(now);
rateLimiter.set(ip, recent);
return true;
}