Skip to content
Start with 100 free verification credits
Qualisend
All articles
Guides / June 28, 2026

How to verify emails in WordPress forms

7 minutes read

Qualisend team
Diagram of a WordPress form submission flowing through a submit hook to the Qualisend verify API and returning deliverable, risky, or undeliverable verdicts.

Every WordPress form plugin will happily collect asdf@asdf and a hundred typo'd Gmail addresses, then hand them straight to your mailing list. To verify emails in WordPress forms you don't need a new plugin — you need to call a verification API at the moment someone submits, or export the entries and clean them in bulk. This guide shows both paths for the big three form plugins (Contact Form 7, WPForms, Gravity Forms) using patterns that work regardless of which one you run.

The short answer#

Two supported patterns, and which one you pick depends on your plugin and its plan:

  1. Real time — hook into the plugin's submit or validation event and call the Qualisend API before the entry is confirmed. On most plugins this is a small PHP snippet on a validation filter (the only place you can reject an address inline), or a webhook step on Pro tiers for async tagging.
  2. Bulk — export the plugin's stored entries to CSV and run them through Qualisend's bulk verifier on a schedule. No code, works on every plan that stores entries.

Verify emails in WordPress forms at submit#

Almost every form plugin fires a server-side event as a submission comes in, and that event is your integration point. The important distinction is when the hook fires, because it decides whether you can block a bad address or only react to it:

Hook typeFiresCan it reject inline?
Validation filter (PHP)Before the entry is savedYes — return a field error the visitor sees
Post-submit action / webhookAfter the entry is savedNo — use it to tag, route, or suppress

If you want the visitor to see "that address doesn't look deliverable" and fix it, you need the validation filter, which means a bit of PHP. If you only want to keep dead addresses out of your downstream tool, a webhook is enough and needs no code.

Here is the validation-filter approach on Contact Form 7's email-validation filter. The same shape ports to Gravity Forms and WPForms — only the hook name (gform_field_validation on Gravity Forms, wpforms_process on WPForms) and the way you attach the error change. If Gravity Forms is your plugin, the verify emails from Gravity Forms guide walks the gform_field_validation hook end to end with the exact GF-specific wiring. The API key lives in a wp-config.php constant, never in a shortcode, theme file, or front-end JavaScript:

// In a snippet plugin, or your theme's functions.php.
// In wp-config.php:  define( 'QUALISEND_API_KEY', 'YOUR_API_KEY' );

add_filter( 'wpcf7_validate_email*', 'qs_verify_email', 20, 2 );
add_filter( 'wpcf7_validate_email',  'qs_verify_email', 20, 2 );

function qs_verify_email( $result, $tag ) {
    $field = $tag->name;
    $email = isset( $_POST[ $field ] ) ? trim( wp_unslash( $_POST[ $field ] ) ) : '';
    if ( $email === '' ) {
        return $result; // let the plugin's own required-field check handle it
    }

    // Check /developers for the exact endpoint and request body.
    $response = wp_remote_post( 'https://api.qualisend.com/v1/verify', array(
        'timeout' => 4, // don't let a slow probe stall the form
        'headers' => array(
            'Authorization' => 'Bearer ' . QUALISEND_API_KEY,
            'Content-Type'  => 'application/json',
        ),
        'body' => wp_json_encode( array( 'email' => $email ) ),
    ) );

    // Fail open: never block a real visitor because our API had a bad moment.
    if ( is_wp_error( $response ) || wp_remote_retrieve_response_code( $response ) !== 200 ) {
        return $result;
    }

    $data    = json_decode( wp_remote_retrieve_body( $response ), true );
    $verdict = $data['result'] ?? array();

    if ( ( $verdict['status'] ?? '' ) === 'undeliverable' ) {
        $result->invalidate( $tag, "That address doesn't look deliverable — please check it." );
    } elseif ( ! empty( $verdict['sub_flags']['disposable'] ) ) {
        $result->invalidate( $tag, 'Please use a permanent email address.' );
    }

    return $result;
}

Three things carry this snippet, and they're the same three in every language: keep the key server-side, cap the request with a short timeout, and fail open — if the call errors, times out, or returns a non-200, let the submission through. A verification API is a quality filter, not a gatekeeper, and losing a real lead to a transient outage is the worse outcome. For the mechanics of the API call itself — headers, error handling, response shape — the PHP email validation guide walks the same request end to end.

If custom PHP isn't an option, the no-code alternative is a webhook. If your plugin offers webhooks — Gravity Forms via its Webhooks Add-On, WPForms via the Webhooks addon, both on higher-tier licenses — point the webhook at a small serverless function that holds your key and calls the API. The catch, from the table above: these webhooks fire after the entry is saved, so they can't show an inline error. What they can do is verify asynchronously and act on the verdict — add a tag, skip the autoresponder, or drop undeliverable addresses before they ever reach your email tool. A no-code webhook step (the kind Zapier or Make expose) works the same way: form submission in, API call, verdict out.

Whether a given plugin exposes webhooks or lets you run custom PHP depends entirely on the plugin and its plan — free Contact Form 7 gives you the validation filter but no webhook UI; Gravity Forms and WPForms gate webhooks behind paid add-ons. Check what your tier includes before committing to one route.

Acting on the verdict#

The API returns a result object holding a status of deliverable, risky, undeliverable, or unknown, plus a 0-100 score, a reason code, and sub-flags for disposable, role, free, and catch_all — the same $data['result'] the snippet above reads. Map those to a form action:

VerdictForm action
undeliverableReject inline (validation filter) or drop before send (webhook).
disposable flagReject or flag, depending on how strict your form is — see role, disposable & free addresses.
risky / catch-allAccept, but tag it — send to the catch-all segment carefully.
unknownAccept. The mail server didn't answer — never lose a real submission over it.
deliverableAccept.

The immediate local verdict — syntax, domain, disposable, role — is what you want on a live form: it comes back fast and catches the bulk of bad submissions. The heavier SMTP mailbox probe is better suited to the bulk path below, where a few seconds of latency doesn't matter. If you're weighing why each check sits where it does, how email verification works breaks down the pipeline.

Or verify entries in bulk from a CSV export#

Not every form needs a real-time gate, and some plugins make custom code awkward. The zero-code alternative is to let submissions accumulate and clean them on a schedule.

  1. Export entries to CSV. Gravity Forms has Import/Export → Export Entries; WPForms has an entry export on Pro; Contact Form 7 stores nothing by default, so pair it with the free Flamingo plugin to capture submissions first.
  2. Bulk-verify the CSV. Upload it to Qualisend's bulk verifier, which runs the full pipeline — including the SMTP probe — on every row and hands back a scored file.
  3. Filter and sync. Keep deliverable, review risky, and drop undeliverable before you import the survivors into your email platform.

This is the same workflow as any list clean, just sourced from your form's entry table — the guide to cleaning an email list covers the export-verify-reimport loop in full. Bulk verification is also the right tool for the addresses you already collected before you added a real-time check: run the back catalogue once, then let the submit-time hook keep the list clean from here on.

Real time, bulk, or both#

They solve different problems, so most sites end up wanting both:

  • Real time is prevention. A typo caught at submit is a lead saved with a one-line correction; a dead domain rejected there never becomes a hard bounce that dents your bounce rate.
  • Bulk is cleanup. Addresses decay — people leave jobs, domains lapse — so even a perfectly gated list needs periodic re-verification.

Pairing a submit-time hook with a monthly bulk pass is the same logic as combining verification with a double opt-in flow: stop the obvious junk at the door, and sweep for the rest on a schedule.

Frequently asked questions#

Can I verify emails in Contact Form 7 without a paid add-on?#

Yes. Contact Form 7 exposes the wpcf7_validate_email filter on its free version, so a small PHP snippet like the one above can call the API and reject undeliverable or disposable addresses inline — no add-on required. You do need to be able to add code (via your theme's functions.php or a code-snippet plugin) and to store your API key in wp-config.php.

Can a Gravity Forms or WPForms webhook reject a bad address inline?#

Usually not. Those webhooks fire after the entry is saved, so they run asynchronously and can't show the visitor a validation error. They're ideal for tagging, routing, or suppressing undeliverable addresses before they reach your email tool. For an inline rejection the visitor sees, use the plugin's validation filter with custom PHP instead.

Is there a native Qualisend plugin for WordPress?#

Not at the moment — our native platform integrations are being rebuilt, and a WordPress connector is on the roadmap. Until it ships, the supported approaches are the two in this guide: call the REST API from a form hook, webhook, or serverless function, or export entries to CSV and bulk-verify. Both use the documented API directly.

Should I verify at submit or clean entries in bulk?#

Both, for different reasons. Verifying at submit prevents typos and disposable addresses from ever entering your list, with immediate feedback to the visitor. Bulk verification catches addresses that decayed after they were collected and cleans the back catalogue you gathered before you added a real-time check. A submit-time hook plus a periodic bulk pass covers both.


Ready to wire it up? The free plan includes credits to test both paths, the API reference has the exact /verify request for your hook or serverless function, and the free email checker lets you spot-test a single address before you write a line of code.

Your reputation, protected.

Clean your first list in minutes. 100 free credits, no card required.

Get started