EmailVerify LogoEmailVerify

ActiveCampaign

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

EmailVerify를 ActiveCampaign과 통합하여 이메일 주소를 검증하고, 연락처 목록을 정리하고, 이메일 전달률을 개선하세요.

통합 방법

방법적합 대상복잡도
웹훅 자동화실시간 검증낮음
API 통합커스텀 워크플로보통
대량 가져오기목록 정리낮음

방법 1: 웹훅 자동화

연락처가 추가될 때 이메일을 검증하는 자동화를 생성하세요.

웹훅 액션 생성

  1. AutomationsNew Automation 이동
  2. 트리거 선택 (예: "Subscribes to a list")
  3. 액션 추가 → Conditions and WorkflowWebhook
  4. 웹훅 구성:
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;

  // Update contact in ActiveCampaign based on result
  const acApiUrl = process.env.ACTIVECAMPAIGN_API_URL;
  const acApiKey = process.env.ACTIVECAMPAIGN_API_KEY;

  try {
    // Find contact by email
    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' });
    }

    // Update contact with verification status
    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),
    });

    // Add tag based on status
    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) {
  // First, find or create the tag
  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) {
    // Create tag if it doesn't exist
    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;
  }

  // Add tag to contact
  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) {
    // Get contact details
    const contact = await this.getContact(contactId);

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

    // Verify email
    const result = await this.bv.verify({ email: contact.email });

    // Update contact with results
    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(),
    });

    // Apply automation based on result
    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) {
    // Get custom field IDs
    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) {
    // Find automation by name
    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) {
    // Get all contacts in list
    const contacts = await this.getListContacts(listId);
    const emails = contacts.map(c => c.email);

    // Bulk verify
    const job = await this.bv.verifyBulk(emails);

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

    // Get results and update contacts
    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';

// Verify single contact
const result = await activeCampaign.verifyContact('12345');
console.log(`Email status: ${result.status}`);

// Verify entire list
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">Email Address</label>
    <input type="email" id="email" name="email" required />
    <span id="email-status"></span>
  </div>

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

  <button type="submit" id="submit-btn">Subscribe</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 = 'Verifying...';
  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 = '✓ Valid email';
      emailStatus.className = 'valid';
      emailValid = true;
    } else {
      emailStatus.textContent = '✗ Please enter a valid email';
      emailStatus.className = 'invalid';
      emailValid = false;
    }
  } catch (error) {
    // Allow submission on API error
    emailStatus.textContent = '';
    emailValid = true;
  }

  submitBtn.disabled = false;
});

form.addEventListener('submit', function(e) {
  if (!emailValid) {
    e.preventDefault();
    emailStatus.textContent = 'Please enter a valid email address';
    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>

자동화 워크플로

구독 시 검증

Trigger: Contact subscribes to list

Action: Webhook to EmailVerify

Wait: Until webhook response

If/Else: Check email_status field
  ├─ If "valid": Continue to welcome email
  └─ If "invalid": Add to "Invalid Emails" list, End

정기적인 목록 정리

Trigger: Run once per month

Action: Webhook to start bulk verification

Wait: 24 hours (for bulk job completion)

Goal: Bulk verification complete

Action: Process results via webhook callback

재참여 캠페인

Trigger: Contact hasn't opened email in 90 days

Action: Verify email address

If/Else: Email status
  ├─ If "valid": Send re-engagement email
  └─ If "invalid": Unsubscribe contact

커스텀 필드 설정

ActiveCampaign에서 다음 커스텀 필드를 생성하세요:

필드 이름유형개인화 태그
Email StatusText%EMAIL_STATUS%
Email ScoreNumber%EMAIL_SCORE%
Email DisposableDropdown (Yes/No)%EMAIL_DISPOSABLE%
Email Verified AtDate%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 }),
    });
  }
}

세분화

이메일 검증 상태에 따라 세그먼트를 생성하세요.

유효한 이메일 세그먼트

Conditions:
- Contact field "Email Status" is "valid"
- Contact field "Email Score" is greater than 0.7

무효한 이메일 세그먼트

Conditions:
- Contact field "Email Status" is "invalid"
OR
- Contact field "Email Status" is "unknown"

고위험 이메일 세그먼트

Conditions:
- Contact field "Email Disposable" is "Yes"
OR
- Contact field "Email Score" is less than 0.5

모범 사례

1. 캠페인 전 검증

주요 캠페인 전에 항상 목록을 검증하세요:

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

  // Verify list
  const results = await service.verifyList(listId);

  // Only proceed if invalid rate is acceptable
  const invalidRate = results.invalid / results.total;

  if (invalidRate > 0.05) { // More than 5% invalid
    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);

    // Return unknown status to allow further processing
    return {
      email,
      status: 'unknown',
      error: error.message,
    };
  }
}

관련 리소스

On this page