From signup screening to CRM enrichment and outbound outreach, AI agents need email verification at every step. This guide shows production deployment patterns for Claude, GPT, and custom agents, with error handling, cost control, monitoring, and real API response handling.
AI agents differ from Zapier workflows because they make contextual decisions. An agent can verify an email, detect a typo, correct it, re-verify the correction, and update the CRM record autonomously. Here are the five most common production patterns.
Our MCP server and tool-calling guide showed how to define email verification as a tool that AI agents can invoke. This follow-up covers what happens after that: deploying agents into production signup flows, CRM enrichment pipelines, and outbound outreach systems. Every pattern uses the real email-check.app API endpoint with real response fields, actual error handling, and cost tracking.
All agent patterns in this guide use the same API call. The email-check.app validation endpoint is a GET request with query parameters and an API key header:
# The core API call every agent uses
GET https://api.email-check.app/v1-get-email-details
Header: x-api-key: YOUR_API_KEY
Params: email, verifyMx, verifySmtp, detectName,
suggestDomain, checkDomainAge, timeout
# Response fields agents use for decisions:
# email - the address validated
# validFormat - RFC syntax check
# validMx - MX records exist
# validSmtp - mailbox verified via SMTP
# isDisposable - temporary/throwaway domain
# isFree - gmail.com, yahoo.com, etc.
# detectedName - { firstName, lastName, confidence }
# domainSuggestion - { original, suggested, confidence }
# domainAge - { ageInDays, createdDate, isValid }
# score - 0-100 composite quality ratingClaude agents (via Anthropic's tool use API) can validate emails during signup, detect disposable addresses, correct typos, and make accept/reject/review decisions. The agent receives a tool definition and the email to verify, then returns a structured decision.
// Claude tool definition for signup screening
const emailVerificationTool = {
name: "verify_signup_email",
description: "Validate a signup email address. " +
"Returns deliverability, disposable status, risk " +
"score, typo suggestions, and domain age. Use this " +
"to decide whether to approve, reject, or correct " +
"the email before creating the user account.",
input_schema: {
type: "object",
properties: {
email: {
type: "string",
format: "email",
description: "The signup email to validate"
}
},
required: ["email"]
}
};
// Claude agent handler
async function handleSignupVerification(email) {
const params = new URLSearchParams({
email,
verifyMx: "true",
verifySmtp: "true",
detectName: "true",
suggestDomain: "true",
checkDomainAge: "true",
timeout: "5000"
});
const response = await fetch(
`https://api.email-check.app/v1-get-email-details?${params}`,
{
headers: {
"accept": "application/json",
"x-api-key": process.env.EMAIL_CHECK_API_KEY
}
}
);
if (!response.ok) {
// Agent handles API failures gracefully
return {
decision: "REVIEW",
reason: "API returned " + response.status,
email
};
}
const data = await response.json();
// Decision logic the agent executes
if (data.isDisposable) {
return { decision: "BLOCK", reason: "disposable", email };
}
if (!data.validFormat || !data.validMx) {
return { decision: "BLOCK", reason: "invalid", email };
}
if (data.validSmtp === false) {
return { decision: "BLOCK", reason: "undeliverable", email };
}
if (data.domainSuggestion && data.domainSuggestion.confidence > 0.8) {
return {
decision: "CORRECT",
suggested: data.domainSuggestion.suggested,
confidence: data.domainSuggestion.confidence,
email
};
}
if (data.score < 40) {
return { decision: "REVIEW", reason: "low_score", score: data.score, email };
}
return { decision: "APPROVE", score: data.score, email };
}The key difference from a Zapier workflow: the Claude agent can explain its decision in natural language when a signup is flagged for review. If the security team asks why a particular address was rejected, the agent can reference the specific API fields that triggered the block.
OpenAI's function calling API lets GPT agents enrich CRM records. This pattern validates incoming leads, classifies them by quality tier, and pushes enriched data to the CRM. The agent handles bulk processing with rate limiting and error recovery.
// GPT function definition for CRM enrichment
const enrichLeadFunction = {
name: "enrich_and_classify_lead",
description: "Validate a lead email and classify it " +
"into a quality tier for CRM import. Returns " +
"verification status, risk assessment, name " +
"extraction, and domain intelligence.",
parameters: {
type: "object",
properties: {
email: {
type: "string",
description: "Lead email to verify and enrich"
}
},
required: ["email"]
}
};
// Agent-side execution with error handling
async function enrichLead(email) {
try {
const params = new URLSearchParams({
email,
verifyMx: "true",
verifySmtp: "true",
detectName: "true",
suggestDomain: "true",
checkDomainAge: "true",
timeout: "8000"
});
const res = await fetch(
`https://api.email-check.app/v1-get-email-details?${params}`,
{
headers: {
"accept": "application/json",
"x-api-key": process.env.EMAIL_CHECK_API_KEY
}
}
);
if (res.status === 429) {
// Rate limited — agent backs off and retries
await new Promise(r => setTimeout(r, 1000));
return enrichLead(email);
}
const data = await res.json();
// Tier classification for CRM import
const tier = classifyLeadTier(data);
return {
email: data.email,
tier,
verification: {
format: data.validFormat,
mx: data.validMx,
smtp: data.validSmtp,
disposable: data.isDisposable,
free: data.isFree,
score: data.score
},
enrichment: {
name: data.detectedName?.confidence > 0.6
? data.detectedName : null,
domainAge: data.domainAge?.ageInDays,
suggestion: data.domainSuggestion
},
action: getTierAction(tier)
};
} catch (error) {
// Agent logs failures but does not crash
return {
email,
tier: "unknown",
action: "skip",
error: error.message
};
}
}
function classifyLeadTier(data) {
if (data.isDisposable || !data.validSmtp) return "reject";
if (!data.validMx || !data.validFormat) return "reject";
if (data.score >= 80 && !data.isFree) return "tier_1";
if (data.score >= 60) return "tier_2";
return "tier_3";
}
function getTierAction(tier) {
const actions = {
tier_1: "import_immediately",
tier_2: "import_with_flag",
tier_3: "schedule_reverification",
reject: "discard"
};
return actions[tier] || "skip";
}This pattern processes leads one at a time with built-in retry logic. For bulk imports of 1,000+ leads, wrap the enrichment in a batch processor that manages concurrency:
// Batch processor for agent-led CRM enrichment
async function batchEnrichLeads(emails, concurrency = 20) {
const results = [];
let apiCalls = 0;
let apiCost = 0;
const costPerCall = 0.00117; // Starter plan
for (let i = 0; i < emails.length; i += concurrency) {
const batch = emails.slice(i, i + concurrency);
const batchResults = await Promise.allSettled(
batch.map(email => enrichLead(email))
);
for (const result of batchResults) {
if (result.status === "fulfilled") {
results.push(result.value);
apiCalls++;
apiCost += costPerCall;
} else {
results.push({ error: result.reason?.message });
}
}
// Track cost for budget-aware agents
if (apiCost > 5.0) {
console.warn(`Agent budget warning: $${apiCost.toFixed(2)} spent on ${apiCalls} calls`);
}
}
return { results, apiCalls, apiCost };
}Before sending cold emails, an agent validates the entire outreach list, removes disposable and undeliverable addresses, corrects typos, and segments the list by quality. This prevents hard bounces that damage sender reputation — a critical concern when bounces exceed 5% on cold outreach.
// Outbound list verification agent
async function verifyOutreachList(contacts) {
const verified = [];
const corrected = [];
const removed = [];
for (const contact of contacts) {
const params = new URLSearchParams({
email: contact.email,
verifyMx: "true",
verifySmtp: "true",
suggestDomain: "true",
detectName: "true",
timeout: "5000"
});
const res = await fetch(
`https://api.email-check.app/v1-get-email-details?${params}`,
{
headers: {
"accept": "application/json",
"x-api-key": process.env.EMAIL_CHECK_API_KEY
}
}
);
const data = await res.json();
if (data.isDisposable || data.validSmtp === false) {
removed.push({
email: contact.email,
reason: data.isDisposable ? "disposable" : "undeliverable"
});
continue;
}
// Apply typo corrections for high-confidence suggestions
if (data.domainSuggestion?.confidence > 0.8) {
corrected.push({
original: contact.email,
corrected: contact.email.replace(
data.domainSuggestion.original,
data.domainSuggestion.suggested
),
confidence: data.domainSuggestion.confidence
});
contact.email = contact.email.replace(
data.domainSuggestion.original,
data.domainSuggestion.suggested
);
}
// Classify for outreach sequencing
contact.quality = data.score >= 80 ? "primary"
: data.score >= 50 ? "secondary" : "risky";
// Enrich with extracted name if confidence is high
if (data.detectedName?.confidence > 0.7) {
contact.firstName = data.detectedName.firstName || contact.firstName;
contact.lastName = data.detectedName.lastName || contact.lastName;
}
verified.push(contact);
}
return {
verified,
corrected,
removed,
stats: {
total: contacts.length,
verifiedCount: verified.length,
correctedCount: corrected.length,
removedCount: removed.length,
removalRate: (removed.length / contacts.length * 100).toFixed(1) + "%"
}
};
}Agents that call external APIs in production need robust error handling. The main failure modes are:
timeoutquery parameter (max 10000ms) and add a client-side timeout of 15 seconds. If the API does not respond, treat the email as "unknown" and proceed without blocking the user.// Production-grade API client for agents
async function verifyEmailWithRetry(email, maxRetries = 3) {
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 15000);
try {
const params = new URLSearchParams({
email,
verifyMx: "true",
verifySmtp: "true",
timeout: "5000"
});
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
const res = await fetch(
`https://api.email-check.app/v1-get-email-details?${params}`,
{
headers: {
"accept": "application/json",
"x-api-key": process.env.EMAIL_CHECK_API_KEY
},
signal: controller.signal
}
);
if (res.status === 401) {
throw new Error("INVALID_API_KEY");
}
if (res.status === 429 && attempt < maxRetries) {
const delay = Math.pow(2, attempt) * 1000;
await new Promise(r => setTimeout(r, delay));
continue;
}
return await res.json();
} catch (fetchError) {
if (fetchError.name === "AbortError") {
return { email, error: "timeout", decision: "REVIEW" };
}
if (fetchError.message === "INVALID_API_KEY") throw fetchError;
if (attempt === maxRetries) {
return { email, error: fetchError.message, decision: "REVIEW" };
}
}
}
} finally {
clearTimeout(timeout);
}
}AI agents can burn through API credits fast if left unchecked. At $0.00117 per verification on the Starter plan, processing 10,000 emails costs $11.70. Build budget tracking into every agent pipeline:
Production agents need observability. Monitor these metrics:
The MCP server guide covers tool definition architecture — how to expose email verification as a tool that any MCP-compatible agent can discover and invoke. This guide covers production deployment: error handling, cost tracking, bulk processing, monitoring, and specific agent framework patterns for Claude, GPT, and custom agents.
Yes. Use the batch processor pattern with concurrency of 20-50 requests and rate limiting. Process large lists over several hours using a scheduler or cron trigger rather than processing everything in a single run. Monitor credit consumption to stay within your plan.
Cache results by email address for 24-72 hours. The email-check.app API does not charge for repeated calls, but caching reduces latency and API load. In CRM workflows, check whether the email was recently verified before calling the API again.
In signup flows, fail open — allow the signup and validate asynchronously. In CRM enrichment, skip the record and log it for retry. In outbound verification, exclude the unverified email from the send list. Never block a user action because an external API is temporarily unavailable unless verification is a hard security requirement (e.g., fraud prevention with disposable detection, where failing closed is appropriate).
Five production patterns for embedding email verification into AI agent workflows. Each pattern addresses a different business function, from signup screening to outbound outreach.
| Pattern | Trigger | API Calls | Error Strategy |
|---|---|---|---|
| Signup Screening | User submits form | 1 per signup | Fail open |
| CRM Enrichment | New lead imported | 1 per lead | Skip and log |
| Outbound Verification | Pre-campaign | 1 per contact | Exclude from send |
| Pre-Campaign Cleaning | Scheduled / manual | Full list | Retry queue |
| Fraud Screening | Real-time | 1 per event | Fail closed |
The email-check.app API returns structured results in under 25ms, with SMTP verification, disposable detection, typo correction, and risk scoring built into every call. Get an API key and start building.