EmailVerify LogoEmailVerify

ActiveCampaign

Email checker for ActiveCampaign. Verify contacts in your email marketing automation.

将 EmailVerify 与 ActiveCampaign 集成,验证邮箱地址、清理联系人列表并提高邮件送达率。

集成方法

方法适用场景复杂度
Webhook 自动化实时验证
API 集成自定义工作流
批量导入列表清理

方法 1:Webhook 自动化

创建一个在添加联系人时验证邮箱的自动化流程。

创建 Webhook 操作

  1. 前往 AutomationsNew Automation
  2. 选择触发器(例如"订阅列表")
  3. 添加操作 → Conditions and WorkflowWebhook
  4. 配置 Webhook:
URL: https://api.emailverify.ai/v1/verify
Method: POST
Headers:
  Authorization: Bearer YOUR_API_KEY
  Content-Type: application/json
Body:
{
  "email": "%EMAIL%",
  "webhook_url": "https://yoursite.com/api/activecampaign/callback"
}

创建回调处理器

处理来自 EmailVerify 的验证结果。

// pages/api/activecampaign/callback.js
import crypto from 'crypto';

export default async function handler(req, res) {
  if (req.method !== 'POST') {
    return res.status(405).json({ error: 'Method not allowed' });
  }

  const { email, status, result } = req.body;

  // 根据验证结果更新 ActiveCampaign 中的联系人
  const acApiUrl = process.env.ACTIVECAMPAIGN_API_URL;
  const acApiKey = process.env.ACTIVECAMPAIGN_API_KEY;

  try {
    // 通过邮箱查找联系人
    const searchResponse = await fetch(
      `${acApiUrl}/api/3/contacts?email=${encodeURIComponent(email)}`,
      {
        headers: {
          'Api-Token': acApiKey,
        },
      }
    );

    const searchData = await searchResponse.json();
    const contact = searchData.contacts[0];

    if (!contact) {
      return res.status(404).json({ error: 'Contact not found' });
    }

    // 使用验证状态更新联系人
    const fieldUpdates = {
      contact: {
        fieldValues: [
          {
            field: process.env.AC_FIELD_EMAIL_STATUS,
            value: status,
          },
          {
            field: process.env.AC_FIELD_EMAIL_SCORE,
            value: result.score?.toString() || '',
          },
        ],
      },
    };

    await fetch(`${acApiUrl}/api/3/contacts/${contact.id}`, {
      method: 'PUT',
      headers: {
        'Api-Token': acApiKey,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify(fieldUpdates),
    });

    // 根据状态添加标签
    const tagName = status === 'valid' ? 'Email Verified' : 'Email Invalid';
    await addTagToContact(contact.id, tagName, acApiUrl, acApiKey);

    res.status(200).json({ success: true });
  } catch (error) {
    console.error('ActiveCampaign update error:', error);
    res.status(500).json({ error: 'Update failed' });
  }
}

async function addTagToContact(contactId, tagName, apiUrl, apiKey) {
  // 首先,查找或创建标签
  const tagResponse = await fetch(
    `${apiUrl}/api/3/tags?search=${encodeURIComponent(tagName)}`,
    {
      headers: { 'Api-Token': apiKey },
    }
  );

  const tagData = await tagResponse.json();
  let tagId = tagData.tags[0]?.id;

  if (!tagId) {
    // 如果标签不存在则创建
    const createResponse = await fetch(`${apiUrl}/api/3/tags`, {
      method: 'POST',
      headers: {
        'Api-Token': apiKey,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        tag: { tag: tagName, tagType: 'contact' },
      }),
    });
    const createData = await createResponse.json();
    tagId = createData.tag.id;
  }

  // 将标签添加到联系人
  await fetch(`${apiUrl}/api/3/contactTags`, {
    method: 'POST',
    headers: {
      'Api-Token': apiKey,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      contactTag: { contact: contactId, tag: tagId },
    }),
  });
}

方法 2:API 集成

使用两个 API 构建自定义集成。

ActiveCampaign 服务

// services/activecampaign.js
import EmailVerify from '@emailverify/sdk';

class ActiveCampaignService {
  constructor() {
    this.apiUrl = process.env.ACTIVECAMPAIGN_API_URL;
    this.apiKey = process.env.ACTIVECAMPAIGN_API_KEY;
    this.bv = new EmailVerify(process.env.EMAILVERIFY_API_KEY);
  }

  async verifyContact(contactId) {
    // 获取联系人详情
    const contact = await this.getContact(contactId);

    if (!contact?.email) {
      throw new Error('Contact has no email');
    }

    // 验证邮箱
    const result = await this.bv.verify({ email: contact.email });

    // 使用验证结果更新联系人
    await this.updateContactFields(contactId, {
      email_status: result.status,
      email_score: result.score,
      email_disposable: result.is_disposable ? 'Yes' : 'No',
      email_verified_at: new Date().toISOString(),
    });

    // 根据验证结果应用自动化
    if (result.status === 'invalid') {
      await this.addToAutomation(contactId, 'Invalid Email Cleanup');
    }

    return result;
  }

  async getContact(contactId) {
    const response = await fetch(
      `${this.apiUrl}/api/3/contacts/${contactId}`,
      {
        headers: { 'Api-Token': this.apiKey },
      }
    );
    const data = await response.json();
    return data.contact;
  }

  async updateContactFields(contactId, fields) {
    const fieldValues = await this.mapToFieldValues(fields);

    await fetch(`${this.apiUrl}/api/3/contacts/${contactId}`, {
      method: 'PUT',
      headers: {
        'Api-Token': this.apiKey,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        contact: { fieldValues },
      }),
    });
  }

  async mapToFieldValues(fields) {
    // 获取自定义字段 ID
    const customFields = await this.getCustomFields();

    return Object.entries(fields).map(([key, value]) => ({
      field: customFields[key],
      value: String(value),
    }));
  }

  async getCustomFields() {
    const response = await fetch(`${this.apiUrl}/api/3/fields`, {
      headers: { 'Api-Token': this.apiKey },
    });
    const data = await response.json();

    return data.fields.reduce((acc, field) => {
      acc[field.perstag.toLowerCase()] = field.id;
      return acc;
    }, {});
  }

  async addToAutomation(contactId, automationName) {
    // 通过名称查找自动化
    const response = await fetch(
      `${this.apiUrl}/api/3/automations?search=${encodeURIComponent(automationName)}`,
      {
        headers: { 'Api-Token': this.apiKey },
      }
    );
    const data = await response.json();
    const automation = data.automations[0];

    if (automation) {
      await fetch(`${this.apiUrl}/api/3/contactAutomations`, {
        method: 'POST',
        headers: {
          'Api-Token': this.apiKey,
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          contactAutomation: {
            contact: contactId,
            automation: automation.id,
          },
        }),
      });
    }
  }

  async verifyList(listId) {
    // 获取列表中的所有联系人
    const contacts = await this.getListContacts(listId);
    const emails = contacts.map(c => c.email);

    // 批量验证
    const job = await this.bv.verifyBulk(emails);

    // 等待完成
    let status;
    do {
      await new Promise(resolve => setTimeout(resolve, 5000));
      status = await this.bv.getBulkJobStatus(job.job_id);
    } while (status.status !== 'completed');

    // 获取结果并更新联系人
    const results = await this.bv.getBulkJobResults(job.job_id);

    for (const result of results.results) {
      const contact = contacts.find(c => c.email === result.email);
      if (contact) {
        await this.updateContactFields(contact.id, {
          email_status: result.status,
          email_score: result.score,
        });
      }
    }

    return {
      total: results.results.length,
      valid: results.results.filter(r => r.status === 'valid').length,
      invalid: results.results.filter(r => r.status === 'invalid').length,
    };
  }

  async getListContacts(listId) {
    const contacts = [];
    let offset = 0;
    const limit = 100;

    while (true) {
      const response = await fetch(
        `${this.apiUrl}/api/3/contacts?listid=${listId}&limit=${limit}&offset=${offset}`,
        {
          headers: { 'Api-Token': this.apiKey },
        }
      );
      const data = await response.json();

      if (data.contacts.length === 0) break;

      contacts.push(...data.contacts);
      offset += limit;
    }

    return contacts;
  }
}

export default new ActiveCampaignService();

使用示例

import activeCampaign from './services/activecampaign';

// 验证单个联系人
const result = await activeCampaign.verifyContact('12345');
console.log(`Email status: ${result.status}`);

// 验证整个列表
const listResults = await activeCampaign.verifyList('1');
console.log(`Verified ${listResults.total} contacts`);
console.log(`Valid: ${listResults.valid}, Invalid: ${listResults.invalid}`);

方法 3:表单集成

在提交 ActiveCampaign 表单之前验证邮箱。

自定义表单处理器

<!-- ActiveCampaign Form with EmailVerify -->
<form id="ac-form" action="https://yoursite.activehosted.com/proc.php" method="POST">
  <input type="hidden" name="u" value="1" />
  <input type="hidden" name="f" value="1" />
  <input type="hidden" name="s" />
  <input type="hidden" name="c" value="0" />
  <input type="hidden" name="m" value="0" />
  <input type="hidden" name="act" value="sub" />
  <input type="hidden" name="v" value="2" />

  <div class="form-group">
    <label for="email">邮箱地址</label>
    <input type="email" id="email" name="email" required />
    <span id="email-status"></span>
  </div>

  <div class="form-group">
    <label for="fullname">姓名</label>
    <input type="text" id="fullname" name="fullname" />
  </div>

  <button type="submit" id="submit-btn">订阅</button>
</form>

<script>
const form = document.getElementById('ac-form');
const emailInput = document.getElementById('email');
const emailStatus = document.getElementById('email-status');
const submitBtn = document.getElementById('submit-btn');

let emailValid = false;

emailInput.addEventListener('blur', async function() {
  const email = this.value;
  if (!email) return;

  emailStatus.textContent = '验证中...';
  emailStatus.className = 'verifying';
  submitBtn.disabled = true;

  try {
    const response = await fetch('/api/verify-email', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ email }),
    });

    const result = await response.json();

    if (result.status === 'valid') {
      emailStatus.textContent = '✓ 邮箱有效';
      emailStatus.className = 'valid';
      emailValid = true;
    } else {
      emailStatus.textContent = '✗ 请输入有效的邮箱地址';
      emailStatus.className = 'invalid';
      emailValid = false;
    }
  } catch (error) {
    // API 错误时允许提交
    emailStatus.textContent = '';
    emailValid = true;
  }

  submitBtn.disabled = false;
});

form.addEventListener('submit', function(e) {
  if (!emailValid) {
    e.preventDefault();
    emailStatus.textContent = '请输入有效的邮箱地址';
    emailStatus.className = 'invalid';
  }
});
</script>

<style>
.form-group {
  margin-bottom: 1rem;
}

#email-status {
  display: block;
  margin-top: 0.25rem;
  font-size: 0.875rem;
}

#email-status.verifying { color: #666; }
#email-status.valid { color: #28a745; }
#email-status.invalid { color: #dc3545; }

button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
</style>

自动化工作流

订阅时验证

触发器: 联系人订阅列表

操作: Webhook 调用 EmailVerify

等待: 直到收到 Webhook 响应

条件判断: 检查 email_status 字段
  ├─ 如果"valid": 继续发送欢迎邮件
  └─ 如果"invalid": 添加到"无效邮箱"列表,结束

定期列表清理

触发器: 每月运行一次

操作: Webhook 启动批量验证

等待: 24 小时(等待批量任务完成)

目标: 批量验证完成

操作: 通过 Webhook 回调处理结果

重新激活活动

触发器: 联系人 90 天未打开邮件

操作: 验证邮箱地址

条件判断: 邮箱状态
  ├─ 如果"valid": 发送重新激活邮件
  └─ 如果"invalid": 取消订阅联系人

自定义字段设置

在 ActiveCampaign 中创建以下自定义字段:

字段名称类型个性化标签
Email Status文本%EMAIL_STATUS%
Email Score数字%EMAIL_SCORE%
Email Disposable下拉框(是/否)%EMAIL_DISPOSABLE%
Email Verified At日期%EMAIL_VERIFIED_AT%

通过 API 创建字段

async function createCustomFields(apiUrl, apiKey) {
  const fields = [
    { title: 'Email Status', type: 'text', perstag: 'EMAIL_STATUS' },
    { title: 'Email Score', type: 'text', perstag: 'EMAIL_SCORE' },
    { title: 'Email Disposable', type: 'dropdown', perstag: 'EMAIL_DISPOSABLE', options: ['Yes', 'No'] },
    { title: 'Email Verified At', type: 'date', perstag: 'EMAIL_VERIFIED_AT' },
  ];

  for (const field of fields) {
    await fetch(`${apiUrl}/api/3/fields`, {
      method: 'POST',
      headers: {
        'Api-Token': apiKey,
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({ field }),
    });
  }
}

分段

根据邮箱验证状态创建分段。

有效邮箱分段

条件:
- 联系人字段"Email Status"为"valid"
- 联系人字段"Email Score"大于 0.7

无效邮箱分段

条件:
- 联系人字段"Email Status"为"invalid"

- 联系人字段"Email Status"为"unknown"

高风险邮箱分段

条件:
- 联系人字段"Email Disposable"为"Yes"

- 联系人字段"Email Score"小于 0.5

最佳实践

1. 活动前验证

在主要活动前始终验证列表:

async function preCampaignVerification(listId, campaignId) {
  const service = new ActiveCampaignService();

  // 验证列表
  const results = await service.verifyList(listId);

  // 只有在无效率可接受时才继续
  const invalidRate = results.invalid / results.total;

  if (invalidRate > 0.05) { // 无效率超过 5%
    console.warn(`无效率较高: ${(invalidRate * 100).toFixed(1)}%`);
    console.warn('建议在发送前清理列表');
    return false;
  }

  return true;
}

2. 处理速率限制

async function verifyWithRateLimit(contacts) {
  const batchSize = 100;
  const delayMs = 1000;

  for (let i = 0; i < contacts.length; i += batchSize) {
    const batch = contacts.slice(i, i + batchSize);

    await Promise.all(
      batch.map(contact => verifyContact(contact.id))
    );

    if (i + batchSize < contacts.length) {
      await new Promise(resolve => setTimeout(resolve, delayMs));
    }
  }
}

3. 错误处理

async function safeVerify(email) {
  try {
    const result = await bv.verify({ email });
    return result;
  } catch (error) {
    console.error(`验证失败 ${email}:`, error);

    // 返回未知状态以允许进一步处理
    return {
      email,
      status: 'unknown',
      error: error.message,
    };
  }
}

相关资源

On this page