Shopify
Email checker for Shopify. Verify customer emails at checkout and in Shopify apps.
通过验证电子邮件地址,保护您的 Shopify 商店免受虚假账户,减少购物车放弃邮件退信,并改善客户沟通。
为什么在 Shopify 中验证电子邮件?
| 挑战 | 影响 | 解决方案 |
|---|---|---|
| 虚假账户 | 促销滥用、欺诈 | 在注册时验证 |
| 购物车放弃 | 恢复邮件退信 | 在发送前验证 |
| 订单通知 | 交付更新失败 | 在结账时验证 |
| 营销活动 | 低可送达性 | 清理客户列表 |
集成方式
| 方式 | 最佳用途 | 复杂度 |
|---|---|---|
| Shopify Flow | 自动化工作流程 | 低 |
| Shopify Functions | 结账验证 | 中等 |
| 第三方应用 | 完整解决方案 | 低 |
| 自定义应用 | 完全控制 | 高 |
方式 1:Shopify Flow(推荐)
使用 Shopify Flow 自动验证电子邮件。
验证新客户电子邮件
创建工作流以在客户注册时验证电子邮件:
触发器: 客户创建
条件: 客户电子邮件不为空
操作:
- 向 EmailVerify 发送 HTTP 请求
- 基于结果添加客户标签
流程配置
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)在购物车放弃邮件前验证
工作流程:在放弃前验证邮件
触发器:
事件:结账放弃
延迟:1 小时
条件:
- 客户电子邮件不为空
- 客户没有标签 "email_invalid"
操作 1:
类型:向 EmailVerify 发送 HTTP 请求
正文:{"email": "{{checkout.email}}"}
操作 2:
类型:分支
如果状态 = "valid":
- 继续放弃邮件序列
如果状态 = "invalid":
- 添加标签 "email_invalid"
- 不发送邮件方式 2:使用 Shopify Functions 进行结账验证
创建 Shopify Function 以在结账期间验证电子邮件。
步骤 1:创建购物车转换函数
// 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: [] };
}
// 注意:用于实时验证,使用预验证缓存
// 或通过 metafield 实现异步验证
return {
operations: [],
};
}步骤 2:创建结账 UI 扩展
// 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">
请检查您的电子邮件地址。它似乎无效。
</Banner>
);
}
if (validationStatus.result?.disposable) {
return (
<Banner status="info">
我们建议为订单更新使用永久电子邮件。
</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();
}方式 3:自定义 Shopify 应用
构建完整的电子邮件验证解决方案。
应用后端(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"
}
]
}
}
});
}Webhook Handler
Handle customer creation webhooks:
// 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);
}
}主题集成 (Liquid)
将验证添加到注册表单:
{% 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;
// 显示加载状态
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();
// 基于结果更新 UI
updateEmailFieldUI(verificationResult);
} catch (error) {
console.error('验证失败:', error);
} finally {
emailInput.classList.remove('verifying');
}
});
function updateEmailFieldUI(result) {
// 删除现有消息
const existingMessage = document.querySelector('.email-verification-message');
if (existingMessage) existingMessage.remove();
// 创建消息元素
const message = document.createElement('div');
message.className = 'email-verification-message';
if (result.status === 'invalid') {
message.classList.add('error');
message.textContent = '请输入有效的电子邮件地址';
submitButton.disabled = true;
} else if (result.result?.disposable) {
message.classList.add('warning');
message.textContent = '请为账户恢复使用永久电子邮件';
} else if (result.status === 'valid') {
message.classList.add('success');
message.textContent = '✓ 电子邮件已验证';
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>应用场景
1. 防止虚假账户注册
在注册期间阻止一次性和无效电子邮件:
// 主题应用扩展
async function validateRegistration(email) {
const result = await verifyEmail(email);
if (result.status === 'invalid') {
return {
valid: false,
message: '请输入有效的电子邮件地址',
};
}
if (result.result.disposable) {
return {
valid: false,
message: '不允许使用临时电子邮件地址',
};
}
return { valid: true };
}2. 购物车放弃恢复
仅向有效地址发送放弃电子邮件:
Shopify Flow:
触发器:结账放弃(1 小时延迟)
条件:检查电子邮件验证状态
如果有效:
→ 发送放弃邮件
→ 添加到再营销受众
如果无效:
→ 跳过电子邮件
→ 记录用于分析3. 订单风险评估
将电子邮件质量纳入欺诈检测:
function calculateOrderRiskScore(order, emailVerification) {
let riskScore = 0;
// 电子邮件验证因素
if (emailVerification.status === 'invalid') {
riskScore += 30;
}
if (emailVerification.result?.disposable) {
riskScore += 20;
}
if (emailVerification.result?.free && order.total > 500) {
riskScore += 10; // 使用免费电子邮件的高价值订单
}
// 其他因素...
if (order.billing_address !== order.shipping_address) {
riskScore += 15;
}
return riskScore;
}4. 客户分段
根据电子邮件质量创建客户分段:
| 分段 | 标准 | 营销策略 |
|---|---|---|
| 高价值 | 已验证、商业电子邮件 | 高级营销活动 |
| 标准 | 已验证、免费电子邮件 | 常规营销活动 |
| 风险 | 未验证、旧账户 | 重新验证活动 |
| 排除 | 无效、一次性 | 无营销 |
Metafield 设置
创建 metafield 以存储验证数据:
客户 Metafields
mutation createMetafieldDefinitions {
metafieldDefinitionCreate(definition: {
namespace: "email_verification"
key: "status"
name: "电子邮件验证状态"
type: "single_line_text_field"
ownerType: CUSTOMER
}) {
createdDefinition { id }
}
}建议的 metafields:
| 命名空间 | 键 | 类型 | 描述 |
|---|---|---|---|
| email_verification | status | single_line_text_field | 有效、无效、未知 |
| email_verification | score | number_decimal | 0.0 - 1.0 |
| email_verification | verified_at | date_time | 最后验证日期 |
| email_verification | disposable | boolean | 是否为一次性电子邮件 |
| email_verification | role_based | boolean | 是否为基于角色的电子邮件 |
在 Liquid 中访问 Metafields
{% if customer.metafields.email_verification.status == 'valid' %}
<span class="verified-badge">✓ 已验证</span>
{% endif %}批量客户验证
清理您现有的客户列表:
导出客户
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;
// 筛选未验证的客户
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;
}批量验证和更新
async function bulkVerifyCustomers(customers) {
const emails = customers.map((c) => c.email);
// 提交批量验证任务
const job = await emailVerify.verifyBulk(emails);
// 等待完成
const results = await waitForJobCompletion(job.job_id);
// 使用结果更新客户
for (const result of results) {
const customer = customers.find((c) => c.email === result.email);
if (customer) {
await updateCustomerVerificationStatus(customer.id, result);
}
}
return results;
}最佳实践
1. 在多个点进行验证
- 注册:阻止虚假账户
- 结账:确保订单通知到达客户
- 购物车放弃:不要在无效地址上浪费电子邮件
2. 缓存结果
缓存验证结果以避免冗余的 API 调用:
const CACHE_DURATION = 24 * 60 * 60 * 1000; // 24 小时
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. 处理边界情况
function handleVerificationResult(result, context) {
switch (result.status) {
case 'valid':
// 正常流程
break;
case 'invalid':
if (context === 'checkout') {
// 不阻止结账,只记录
logInvalidEmail(result.email, 'checkout');
} else if (context === 'registration') {
// 阻止注册
throw new Error('无效的电子邮件');
}
break;
case 'unknown':
// 接受但标记为审查
flagForReview(result.email);
break;
case 'accept_all':
// 有效但监控退信
markAsCatchAll(result.email);
break;
}
}4. 监控和优化
跟踪这些指标:
- 验证成功率
- 退信率降低
- 虚假账户防止率
- 购物车放弃电子邮件可递送性