Skip to content

LangChain

Terminal window
npm install @langchain/core truval
import { tool } from '@langchain/core/tools'
import { z } from 'zod'
const verifyEmailTool = tool(
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 }),
})
return res.json()
},
{
name: 'verify_email',
description: 'Verify if an email address is real and deliverable. Returns valid, confidence score, and whether the address is disposable or a role address.',
schema: z.object({
email: z.string().email().describe('The email address to verify'),
}),
}
)

An agent shouldn’t just fetch the validation status; it should act on it. Here is an example of a LangGraph agent that handles typos, rejects disposable emails, and asks for confirmation on low confidence scores.

import { ChatOpenAI } from '@langchain/openai'
import { createReactAgent } from '@langchain/langgraph/prebuilt'
const agent = createReactAgent({
llm: new ChatOpenAI({ model: 'gpt-5.4' }),
tools: [verifyEmailTool],
stateModifier: `You are an onboarding agent. Your goal is to collect a valid email address.
Always verify the email before proceeding. Use status, mx_found, smtp_blocked, not confidence alone.
- If suggestion is present, ask "Did you mean [suggestion]?"
- If disposable is true, reject and ask for a real email.
- If status is invalid or undeliverable, ask for a different email.
- If catch_all or status is catch_all, ask the user to confirm.
- If status is unknown, mx_found is true, and smtp_blocked is false (often confidence 0.50), ask the user to confirm — not invalid.
- If smtp_blocked is true with confidence ~0.75, accept.
- If confidence < 0.50 after the above, ask for a different email.
- If confidence >= 0.9 (deliverable), accept and proceed.`,
})
const result = await agent.invoke({
messages: [{ role: 'user', content: 'My email is test@mailinator.com' }],
})
// The agent runs the tool, sees disposable: true, and autonomously
// asks the user for a non-throwaway address.
const verifyEmailTool = tool(
async ({ email, min_confidence = 0.7 }) => {
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 }),
})
const data = await res.json()
const inconclusive =
data.status === 'unknown' && data.mx_found && !data.smtp_blocked
const blockedOk = data.smtp_blocked && data.confidence >= 0.7
if (
data.confidence < min_confidence &&
!inconclusive &&
!blockedOk &&
data.status !== 'catch_all' &&
!data.catch_all
) {
return { ...data, recommendation: 'low confidence — consider rejecting' }
}
return data
},
{
name: 'verify_email',
description: 'Verify email deliverability with confidence scoring.',
schema: z.object({
email: z.string().email(),
min_confidence: z.number().min(0).max(1).optional()
.describe('Minimum confidence threshold (default: 0.7)'),
}),
}
)
Terminal window
TRUVAL_API_KEY=sk_live_...

Get your API key at dash.truval.dev.