Skip to content

Building an email validation agent

When building an AI agent that collects or processes emails, checking if they are valid is crucial before taking action.

This guide walks through creating an end-to-end agent workflow that verifies an email, handles typos, rejects disposable addresses, and proceeds when confident.

Our agent will accomplish the following:

  1. Ask the user for an email address.
  2. Verify the email using truval.dev.
  3. If there is a typo suggestion, ask the user to confirm the correction.
  4. If it’s a disposable address, reject it and ask for a real one.
  5. If status is undeliverable or invalid, reject and ask for another address.
  6. If status is unknown with mx_found and not smtp_blocked (typical confidence 0.50), ask the user to confirm — not the same as invalid.
  7. If catch-all or low confidence in other cases, ask for confirmation or a different address per the Agent decision guide.
  8. If high confidence or smtp_blocked with ~0.75, proceed (see agent guide).

Here is a complete, runnable example using the Vercel AI SDK and OpenAI.

import { generateText, tool } from 'ai';
import { openai } from '@ai-sdk/openai';
import { z } from 'zod';
const agent = async (userInput: string) => {
const result = await generateText({
model: openai('gpt-5.4'),
system: `You are an onboarding agent. Your goal is to collect a valid email address from the user.
Always use the verify_email tool before accepting an email.
Rules:
- If the tool returns a suggestion, ask the user if they meant the suggested email.
- If disposable is true, refuse temporary addresses.
- If status is invalid or undeliverable, ask for a different email.
- If catch_all or status is catch_all, ask the user to confirm (mailbox not proven).
- If status is unknown, mx_found is true, and smtp_blocked is false (often confidence 0.50), ask the user to confirm — do not call it invalid.
- If smtp_blocked is true and confidence is around 0.75, accept (major provider).
- If confidence >= 0.9 (deliverable), accept and say "Email accepted, onboarding complete."
- If confidence is between 0.7 and 0.9 without the cases above, proceed with a short warning if needed.`,
prompt: userInput,
tools: {
verify_email: tool({
description: 'Verify an email address before accepting it.',
parameters: z.object({
email: z.string().email(),
}),
execute: async ({ email }) => {
const res = await fetch('https://api.truval.dev/v1/email/verify', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.TRUVAL_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ email }),
});
if (!res.ok) {
throw new Error('Failed to verify email');
}
return res.json();
},
}),
},
maxSteps: 3, // Enable multi-step tool calls
});
return result.text;
};
// Example interactions:
// User input: "My email is user@gnail.com"
// Agent runs tool, gets suggestion "user@gmail.com"
// Agent output: "It looks like there might be a typo. Did you mean user@gmail.com?"
// User input: "I'll use test@mailinator.com"
// Agent runs tool, gets disposable: true
// Agent output: "I cannot accept temporary or disposable email addresses. Please provide a real one."
// User input: "hello@truval.dev"
// Agent runs tool, gets high confidence (e.g. deliverable)
// Agent output: "Email accepted, onboarding complete."

Agents act autonomously. If your agent is tasked with adding a user to a CRM or sending out a welcome sequence, bouncing emails can severely harm your sender reputation.

By giving your agent the verify_email tool and explicit rules on how to handle the signals (like disposable, suggestion, and confidence), the agent can autonomously course-correct the user before making the final API call to your CRM or email provider.