Shopify
Email checker for Shopify. Verify customer emails at checkout and in Shopify apps.
Proteja su tienda Shopify de cuentas falsas, reduzca rebotes de correos de carritos abandonados y mejore la comunicación con clientes verificando direcciones de correo.
¿Por Qué Verificar Correos en Shopify?
| Desafío | Impacto | Solución |
|---|---|---|
| Cuentas falsas | Abuso de promociones, fraude | Verificar al registrarse |
| Carrito abandonado | Correos de recuperación rebotados | Verificar antes de enviar |
| Notificaciones de pedidos | Actualizaciones de entrega fallidas | Verificar al pagar |
| Campañas de marketing | Baja entregabilidad | Limpiar lista de clientes |
Métodos de Integración
| Método | Mejor Para | Complejidad |
|---|---|---|
| Shopify Flow | Flujos de trabajo automatizados | Baja |
| Shopify Functions | Validación en checkout | Media |
| Aplicación de terceros | Solución completa | Baja |
| Aplicación personalizada | Control completo | Alta |
Método 1: Shopify Flow (Recomendado)
Use Shopify Flow para verificar correos automáticamente.
Verificar Correos de Nuevos Clientes
Cree un flujo de trabajo para verificar correos cuando los clientes se registran:
Disparador: Cliente creado
Condición: El correo del cliente no está en blanco
Acciones:
- Enviar solicitud HTTP a EmailVerify
- Agregar etiqueta de cliente según resultado
Configuración de Flujo
Workflow: Verify New Customer Email
Trigger:
Event: Customer created
Condition:
- Customer email is not blank
Action 1:
Type: Send HTTP request
URL: https://api.emailverify.ai/v1/verify
Method: POST
Headers:
- Authorization: Bearer YOUR_API_KEY
- Content-Type: application/json
Body: {"email": "{{customer.email}}"}
Wait:
Duration: 1 second
Action 2:
Type: Add customer tags
Tags:
- email_verified (if status = valid)
- email_invalid (if status = invalid)Verificar Antes de Correos de Carrito Abandonado
Workflow: Verify Before Abandonment Email
Trigger:
Event: Checkout abandoned
Delay: 1 hour
Condition:
- Customer email is not blank
- Customer does not have tag "email_invalid"
Action 1:
Type: Send HTTP request to EmailVerify
Body: {"email": "{{checkout.email}}"}
Action 2:
Type: Branch
If status = "valid":
- Continue to abandonment email sequence
If status = "invalid":
- Add tag "email_invalid"
- Do not send emailMétodo 2: Validación en Checkout con Shopify Functions
Cree una Shopify Function para validar correos durante el checkout.
Paso 1: Crear una Función de Transformación de Carrito
// extensions/email-validation/src/run.js
import { EmailVerify } from '@emailverify/node';
export function run(input) {
const { cart } = input;
const email = cart?.buyerIdentity?.email;
if (!email) {
return { operations: [] };
}
// Note: For real-time validation, use a pre-validated cache
// or implement async validation via metafield
return {
operations: [],
};
}Paso 2: Crear una Extensión de UI de Checkout
// extensions/email-validation-ui/src/Checkout.jsx
import {
useExtensionApi,
render,
Banner,
BlockStack,
} from '@shopify/checkout-ui-extensions-react';
import { useState, useEffect } from 'react';
render('Checkout::Contact::RenderAfter', () => <EmailValidation />);
function EmailValidation() {
const { buyerIdentity } = useExtensionApi();
const [validationStatus, setValidationStatus] = useState(null);
useEffect(() => {
const email = buyerIdentity?.email?.current;
if (email) {
validateEmail(email).then(setValidationStatus);
}
}, [buyerIdentity?.email?.current]);
if (!validationStatus) return null;
if (validationStatus.status === 'invalid') {
return (
<Banner status="warning">
Please check your email address. It appears to be invalid.
</Banner>
);
}
if (validationStatus.result?.disposable) {
return (
<Banner status="info">
We recommend using a permanent email for order updates.
</Banner>
);
}
return null;
}
async function validateEmail(email) {
const response = await fetch('/apps/email-verify/validate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email }),
});
return response.json();
}Método 3: Aplicación Shopify Personalizada
Construya una solución completa de verificación de correo.
Backend de Aplicación (Node.js)
// server/index.js
import '@shopify/shopify-app-remix/adapters/node';
import { shopifyApp } from '@shopify/shopify-app-remix/server';
import { EmailVerify } from '@emailverify/node';
const shopify = shopifyApp({
// ... Shopify config
});
const emailVerify = new EmailVerify({
apiKey: process.env.EMAILVERIFY_API_KEY,
});
// API route for email verification
export async function action({ request }) {
const { email, customerId } = await request.json();
try {
const result = await emailVerify.verify(email);
// Update customer metafield
if (customerId) {
await updateCustomerVerificationStatus(customerId, result);
}
return json(result);
} catch (error) {
return json({ error: error.message }, { status: 500 });
}
}
async function updateCustomerVerificationStatus(customerId, result) {
const { admin } = await shopify.authenticate.admin(request);
await admin.graphql(`
mutation updateCustomerMetafield($input: CustomerInput!) {
customerUpdate(input: $input) {
customer {
id
}
}
}
`, {
variables: {
input: {
id: `gid://shopify/Customer/${customerId}`,
metafields: [
{
namespace: "email_verification",
key: "status",
value: result.status,
type: "single_line_text_field"
},
{
namespace: "email_verification",
key: "score",
value: String(result.score),
type: "number_decimal"
},
{
namespace: "email_verification",
key: "verified_at",
value: new Date().toISOString(),
type: "date_time"
}
]
}
}
});
}Manejador de Webhook
Maneje webhooks de creación de clientes:
// server/webhooks/customer-created.js
export async function handleCustomerCreated(topic, shop, body) {
const customer = JSON.parse(body);
const { id, email } = customer;
if (!email) return;
try {
// Verify email
const result = await emailVerify.verify(email);
// Update customer with tags
const tags = [];
if (result.status === 'valid') {
tags.push('email_verified');
} else if (result.status === 'invalid') {
tags.push('email_invalid');
}
if (result.result?.disposable) {
tags.push('disposable_email');
}
await updateCustomerTags(shop, id, tags);
// Store verification result
await updateCustomerVerificationStatus(shop, id, result);
console.log(`Verified ${email}: ${result.status}`);
} catch (error) {
console.error(`Failed to verify ${email}:`, error);
}
}Integración de Tema (Liquid)
Agregue verificación al formulario de registro:
{% comment %} snippets/email-verification.liquid {% endcomment %}
<script>
document.addEventListener('DOMContentLoaded', function() {
const emailInput = document.querySelector('input[type="email"]');
const submitButton = document.querySelector('form[action="/account"] button[type="submit"]');
let verificationResult = null;
emailInput.addEventListener('blur', async function() {
const email = this.value;
if (!email) return;
// Show loading state
emailInput.classList.add('verifying');
try {
const response = await fetch('/apps/emailverify/verify', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email })
});
verificationResult = await response.json();
// Update UI based on result
updateEmailFieldUI(verificationResult);
} catch (error) {
console.error('Verification failed:', error);
} finally {
emailInput.classList.remove('verifying');
}
});
function updateEmailFieldUI(result) {
// Remove existing messages
const existingMessage = document.querySelector('.email-verification-message');
if (existingMessage) existingMessage.remove();
// Create message element
const message = document.createElement('div');
message.className = 'email-verification-message';
if (result.status === 'invalid') {
message.classList.add('error');
message.textContent = 'Please enter a valid email address';
submitButton.disabled = true;
} else if (result.result?.disposable) {
message.classList.add('warning');
message.textContent = 'Please use a permanent email for account recovery';
} else if (result.status === 'valid') {
message.classList.add('success');
message.textContent = '✓ Email verified';
submitButton.disabled = false;
}
emailInput.parentNode.appendChild(message);
}
});
</script>
<style>
.email-verification-message {
font-size: 12px;
margin-top: 4px;
}
.email-verification-message.error { color: #c9302c; }
.email-verification-message.warning { color: #f0ad4e; }
.email-verification-message.success { color: #5cb85c; }
input[type="email"].verifying {
background-image: url('/path/to/spinner.gif');
background-position: right 10px center;
background-repeat: no-repeat;
}
</style>Casos de Uso
1. Prevenir Registro de Cuentas Falsas
Bloquee correos desechables e inválidos durante el registro:
// Theme app extension
async function validateRegistration(email) {
const result = await verifyEmail(email);
if (result.status === 'invalid') {
return {
valid: false,
message: 'Please enter a valid email address',
};
}
if (result.result.disposable) {
return {
valid: false,
message: 'Temporary email addresses are not allowed',
};
}
return { valid: true };
}2. Recuperación de Carrito Abandonado
Solo envíe correos de abandono a direcciones válidas:
Shopify Flow:
Trigger: Checkout abandoned (1 hour delay)
Condition: Check email verification status
If valid:
→ Send abandonment email
→ Add to remarketing audience
If invalid:
→ Skip email
→ Log for analytics3. Evaluación de Riesgo de Pedido
Factorice la calidad del correo en la detección de fraude:
function calculateOrderRiskScore(order, emailVerification) {
let riskScore = 0;
// Email verification factors
if (emailVerification.status === 'invalid') {
riskScore += 30;
}
if (emailVerification.result?.disposable) {
riskScore += 20;
}
if (emailVerification.result?.free && order.total > 500) {
riskScore += 10; // High value order with free email
}
// Other factors...
if (order.billing_address !== order.shipping_address) {
riskScore += 15;
}
return riskScore;
}4. Segmentación de Clientes
Cree segmentos de clientes basados en la calidad del correo:
| Segmento | Criterio | Estrategia de Marketing |
|---|---|---|
| Alto Valor | Verificado, correo empresarial | Campañas premium |
| Estándar | Verificado, correo gratuito | Campañas regulares |
| En Riesgo | No verificado, cuenta antigua | Campaña de re-verificación |
| Excluido | Inválido, desechable | Sin marketing |
Configuración de Metafield
Cree metafields para almacenar datos de verificación:
Metafields de Cliente
mutation createMetafieldDefinitions {
metafieldDefinitionCreate(definition: {
namespace: "email_verification"
key: "status"
name: "Email Verification Status"
type: "single_line_text_field"
ownerType: CUSTOMER
}) {
createdDefinition { id }
}
}Metafields recomendados:
| Namespace | Key | Type | Descripción |
|---|---|---|---|
| email_verification | status | single_line_text_field | valid, invalid, unknown |
| email_verification | score | number_decimal | 0.0 - 1.0 |
| email_verification | verified_at | date_time | Fecha de última verificación |
| email_verification | disposable | boolean | Es correo desechable |
| email_verification | role_based | boolean | Es correo basado en rol |
Acceder a Metafields en Liquid
{% if customer.metafields.email_verification.status == 'valid' %}
<span class="verified-badge">✓ Verified</span>
{% endif %}Verificación Masiva de Clientes
Limpie su lista de clientes existente:
Exportar Clientes
async function exportCustomersForVerification(admin) {
const query = `
query getCustomers($cursor: String) {
customers(first: 250, after: $cursor) {
edges {
node {
id
email
createdAt
metafield(namespace: "email_verification", key: "status") {
value
}
}
cursor
}
pageInfo {
hasNextPage
}
}
}
`;
let customers = [];
let cursor = null;
do {
const response = await admin.graphql(query, {
variables: { cursor },
});
const { edges, pageInfo } = response.data.customers;
// Filter unverified customers
const unverified = edges
.filter((e) => !e.node.metafield)
.map((e) => ({
id: e.node.id,
email: e.node.email,
}));
customers.push(...unverified);
cursor = edges[edges.length - 1]?.cursor;
} while (response.data.customers.pageInfo.hasNextPage);
return customers;
}Verificar Masivamente y Actualizar
async function bulkVerifyCustomers(customers) {
const emails = customers.map((c) => c.email);
// Submit bulk verification job
const job = await emailVerify.verifyBulk(emails);
// Wait for completion
const results = await waitForJobCompletion(job.job_id);
// Update customers with results
for (const result of results) {
const customer = customers.find((c) => c.email === result.email);
if (customer) {
await updateCustomerVerificationStatus(customer.id, result);
}
}
return results;
}Mejores Prácticas
1. Verifique en Múltiples Puntos
- Registro: Bloquear cuentas falsas
- Checkout: Asegurar que las notificaciones de pedido lleguen a los clientes
- Carrito abandonado: No desperdiciar correos en direcciones inválidas
2. Almacene Resultados en Caché
Almacene en caché los resultados de verificación para evitar llamadas redundantes a la API:
const CACHE_DURATION = 24 * 60 * 60 * 1000; // 24 hours
async function verifyWithCache(email) {
const cacheKey = `email_verify:${email}`;
const cached = await redis.get(cacheKey);
if (cached) {
return JSON.parse(cached);
}
const result = await emailVerify.verify(email);
await redis.setex(cacheKey, CACHE_DURATION / 1000, JSON.stringify(result));
return result;
}3. Maneje Casos Especiales
function handleVerificationResult(result, context) {
switch (result.status) {
case 'valid':
// Normal flow
break;
case 'invalid':
if (context === 'checkout') {
// Don't block checkout, just log
logInvalidEmail(result.email, 'checkout');
} else if (context === 'registration') {
// Block registration
throw new Error('Invalid email');
}
break;
case 'unknown':
// Accept but flag for review
flagForReview(result.email);
break;
case 'accept_all':
// Valid but monitor for bounces
markAsCatchAll(result.email);
break;
}
}4. Monitoree y Optimice
Rastree estas métricas:
- Tasa de éxito de verificación
- Reducción de tasa de rebote
- Tasa de prevención de cuentas falsas
- Entregabilidad de correo de carrito abandonado