Typeform is great at collecting email addresses and quietly bad at telling you which ones are real. Its email field checks that what someone typed looks like an address — it can't confirm the mailbox exists, isn't disposable, or won't hard-bounce your very first follow-up. This guide shows two practical ways to verify emails from Typeform with Qualisend: in real time, with a webhook that fires the moment a response lands, and in bulk, by exporting responses to a CSV. Neither needs a native plugin — there isn't one yet — just Typeform's built-in webhooks or its export button.
The short answer#
Pick the path that matches when you need the answer:
- Real time — point a Typeform webhook at a small serverless function. On every submission Typeform POSTs the response to your endpoint; the function pulls the email, calls the Qualisend API, and acts on the verdict — tag the contact, route it to the right list, or hold the welcome email for a bad address.
- Bulk — export your existing responses to CSV, run them through Qualisend's bulk verification, and suppress the undeliverables before your next send.
Why Typeform's email field isn't enough#
Typeform's email question type runs a format check in the browser — it makes
sure there's an @, a domain, and no obvious garbage. That's the same class of
check a regex does, and it fails for the same reasons:
format is not deliverability. jane@gmial.com
passes the format check. So does throwaway@mailinator.com, and so does a
real-looking address at a domain that shut down last year.
None of those are caught until you send — and by then a dead address is a hard bounce that chips at your bounce rate and sender reputation. Real verification adds the layers Typeform can't: a DNS/MX lookup and an SMTP mailbox probe, plus flags for disposable, role, and catch-all addresses. If that pipeline is new to you, what email verification actually checks is the primer.
Two ways to verify emails from Typeform#
The important constraint first: Typeform can't block a bad email mid-form. There's no supported way to call an external API between questions and stop a respondent from finishing, so real-time verification happens just after submit, in a webhook — not as an inline gate. That shapes both paths.
| Path | When it runs | Best for |
|---|---|---|
| Real-time webhook | Instantly, per submission | Live funnels — tag, route, or hold follow-up before it sends |
| Bulk CSV | On demand, in batches | Existing response backlogs and periodic list hygiene |
Path 1: real-time with a Typeform webhook#
Typeform can send each response to a URL you control. In the form's Connect
panel, add a webhook and point it at your endpoint. Webhooks are a paid-plan
feature on Typeform, so check your tier before you build. When a response is
submitted, Typeform POSTs a JSON payload whose form_response.answers array
holds each answer — the email address lives in the answer of type email.
Your endpoint is a serverless function that holds the API key and turns the verdict into an action. The pattern is the same one in the verify-at-signup guide: key stays server-side, and you act on the result. Here it is as a Next.js Route Handler (check the developer docs for the exact endpoint path and request shape):
// app/api/typeform-webhook/route.ts
import { NextResponse } from "next/server";
// Placeholder — confirm the real path in /developers.
const QUALISEND_ENDPOINT = "https://api.qualisend.com/v1/verify";
export async function POST(req: Request) {
const payload = await req.json();
// The email lives in the answer whose type is "email".
const answers = payload.form_response?.answers ?? [];
const email = answers.find((a) => a.type === "email")?.email;
if (!email) return NextResponse.json({ ok: true }); // nothing to verify
const res = await fetch(QUALISEND_ENDPOINT, {
method: "POST",
headers: {
// Store YOUR_API_KEY server-side, never in the browser.
Authorization: `Bearer ${process.env.QUALISEND_API_KEY!}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ email }),
signal: AbortSignal.timeout(4000),
});
if (!res.ok) return NextResponse.json({ ok: true, degraded: true }); // fail open
const { result } = await res.json();
// The submit already happened — route on the verdict instead of blocking.
if (result.status === "undeliverable" || result.sub_flags?.disposable) {
// Skip the welcome email, tag the contact for review, keep it off the main list.
}
return NextResponse.json({ ok: true, status: result.status });
}
Three things make this robust. Respond fast: Typeform expects a 2xx
quickly, so keep the handler lean and return promptly. Fail open: if the API
times out or errors, don't lose the lead — accept it and re-check later, which is
why the !res.ok branch still returns ok: true. And verify the signature
Typeform sends so a stranger can't POST fake responses at your endpoint — the
Connect panel gives you a secret for that.
One gotcha in the payload: if your form has more than one email question, or you
want to be robust to reordering, match on the answer's field.ref instead of
grabbing the first type === "email" answer. Set a stable ref on the email
question in the Typeform builder and read a.field?.ref === "your_ref", so the
right address is always the one you verify.
Downstream, the verdict is just a branch. A deliverable result flows straight
into your CRM or email tool; an undeliverable or disposable one gets tagged,
held back from the welcome sequence, or dropped into a review queue — whatever
your process needs. The webhook is the plumbing; the routing is yours.
The verification logic itself is language-agnostic; the same call works from a Python or PHP function if that's your stack. The endpoint code in the Node.js walkthrough or the Python walkthrough drops straight into a webhook handler — only the payload parsing above is Typeform-specific.
Path 2: bulk-verify a CSV export#
If you already have a pile of responses, or you'd rather clean on a schedule than wire up a webhook, go in batches. In Typeform, open Results → Responses and download the data as CSV (or XLSX). You'll get one row per submission with the email in its own column.
Then:
- Upload the CSV to Qualisend's bulk verification and let it run the full pipeline — MX, SMTP, and the disposable/role/catch-all flags — across every row.
- Download the annotated file. Each address comes back with a status, a reason code, and a 0-100 score.
- Suppress the undeliverables in whatever tool you actually mail from, and handle the risky rows with care. The end-to-end routine, including where each status belongs, is in how to clean an email list.
Bulk is the right tool for a backlog, but it's cleanup, not prevention: an address you catch here has usually already been sitting in your list. Pair a periodic bulk pass with the real-time webhook so new bad addresses are flagged the moment they arrive.
Acting on the verdict#
Whichever path delivers the result, the shape is the same — a status, a
reason, a score, and the sub-flags. Map each to an action:
| Result | What to do |
|---|---|
deliverable | Accept — add to your list and send normally. |
undeliverable | Suppress. Don't send; check the reason to see whether it's
a bad domain or a dead mailbox. |
disposable flag | Reject or tag, depending on how strict your funnel is — see role, disposable & free addresses. |
risky / catch-all | Accept but segment. A catch-all domain can't confirm the individual mailbox, so send cautiously. |
unknown | Accept and re-check later — the infrastructure didn't answer, so never drop a real lead over it. |
Frequently asked questions#
Can Typeform verify email addresses on its own?#
Only the format. Typeform's email question type confirms an address is
well-formed — it has an @ and a domain — but it doesn't resolve MX records or
probe the mailbox, so a typo'd or disposable address that looks valid still gets
through. Real verification needs the DNS and SMTP layers a service like Qualisend
adds on top.
Do I need a paid Typeform plan to verify emails in real time?#
For the webhook path, yes — outbound webhooks live in Typeform's Connect panel on its paid tiers, so check your plan before you build the endpoint. If you're on a plan without webhooks, use the bulk path instead: export responses to CSV and verify them in batches, which works on any plan that lets you download results.
Can I block a bad email before the respondent finishes the form?#
Not reliably. Typeform has no supported way to call an external API mid-form and stop someone from submitting, so real-time verification runs just after submit, in the webhook. In practice that's fine: you verify within seconds and act before the address ever receives a message — you hold the welcome email, tag the contact, or route it to review rather than blocking the form itself.
Should I use the real-time webhook or the bulk CSV export?#
Use the webhook when the timing matters — you want to greet, route, or suppress per submission as responses come in. Use bulk when you're cleaning a backlog or running periodic hygiene. Most teams do both: the webhook keeps new sign-ups clean, and an occasional bulk pass catches anything that slipped through or aged out.
Ready to wire it up? Grab a scoped key and the exact request format in the developer docs, sanity-check a single address in the free email checker, or start with the 100 free credits on every plan to test the flow end to end.