ActiveCampaign
Email checker for ActiveCampaign. Verify contacts in your email marketing automation.
EmailVerify を ActiveCampaign と統合して、メールアドレスの検証、連絡先リストのクリーニング、メール到達率の向上を実現します。
統合方法
| 方法 | 最適な用途 | 複雑さ |
|---|---|---|
| Webhook 自動化 | リアルタイム検証 | 低 |
| API 統合 | カスタムワークフロー | 中 |
| 一括インポート | リストクリーニング | 低 |
方法 1: Webhook 自動化
連絡先が追加されたときにメールを検証する自動化を作成します。
Webhook アクションの作成
- 自動化 → 新規自動化 に移動
- トリガーを選択(例:「リストに登録」)
- アクションを追加 → 条件とワークフロー → Webhook
- 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 フォームのメールを検証します。
カスタムフォームハンドラー
<!-- EmailVerify を使用した ActiveCampaign フォーム -->
<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>自動化ワークフロー
登録時の検証
トリガー: 連絡先がリストに登録
↓
アクション: EmailVerify への Webhook
↓
待機: Webhook レスポンスまで
↓
If/Else: email_status フィールドをチェック
├─ "valid" の場合: ウェルカムメールに進む
└─ "invalid" の場合: 「無効なメール」リストに追加、終了定期的なリストクリーニング
トリガー: 月に 1 回実行
↓
アクション: 一括検証を開始する Webhook
↓
待機: 24 時間(一括ジョブ完了まで)
↓
ゴール: 一括検証完了
↓
アクション: Webhook コールバックで結果を処理再エンゲージメントキャンペーン
トリガー: 連絡先が 90 日間メールを開封していない
↓
アクション: メールアドレスを検証
↓
If/Else: メールステータス
├─ "valid" の場合: 再エンゲージメントメールを送信
└─ "invalid" の場合: 連絡先を配信停止カスタムフィールドの設定
ActiveCampaign でこれらのカスタムフィールドを作成します:
| フィールド名 | タイプ | パーソナライズタグ |
|---|---|---|
| Email Status | テキスト | %EMAIL_STATUS% |
| Email Score | 数値 | %EMAIL_SCORE% |
| Email Disposable | ドロップダウン(Yes/No) | %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(`High invalid rate: ${(invalidRate * 100).toFixed(1)}%`);
console.warn('Consider cleaning list before sending');
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(`Verification failed for ${email}:`, error);
// 処理を続行するために unknown ステータスを返す
return {
email,
status: 'unknown',
error: error.message,
};
}
}