{"id":2489,"date":"2026-05-05T14:07:57","date_gmt":"2026-05-05T14:07:57","guid":{"rendered":"https:\/\/www.emailverify.io\/blog\/?p=2489"},"modified":"2026-05-12T06:26:03","modified_gmt":"2026-05-12T06:26:03","slug":"email-verification-api-guide","status":"publish","type":"post","link":"https:\/\/www.emailverify.io\/blog\/email-verification-api-guide\/","title":{"rendered":"Email Verification API: How to Verify Emails at Signup"},"content":{"rendered":"<p>If you&#8217;re a developer responsible for a signup form, this guide is for you. If you\u2019re building a signup flow, email quality is one of the first things that can break it.<\/p>\n<p>Users mistype addresses, bots submit fake emails, and disposable inboxes slip through. Left unchecked, this leads to poor deliverability, wasted campaigns, and unreliable user data.<\/p>\n<p>An email verification API solves this by checking whether an email is actually valid in real time, going beyond basic validation to analyze domain setup, mail servers, and mailbox behavior.<\/p>\n<p>The integration itself is simple. The real challenge is doing it right:<\/p>\n<ul>\n<li>When to trigger verification<\/li>\n<li>How to handle slow responses<\/li>\n<li>What to show users for different outcomes<\/li>\n<\/ul>\n<p>This guide walks through a production-ready approach, covering architecture, UX decisions, and code examples, so you can verify emails without slowing down your signup flow.<\/p>\n<div class=\"info-box box-green\">\n<div class=\"box-label\">TL;DR<\/div>\n<p>An email verification API is an HTTP service that evaluates whether an email address can receive mail by running checks like syntax validation, DNS resolution, MX lookup, SMTP probing, and risk classification.<\/p>\n<p>It returns a structured response with a four-tier status model:<\/p>\n<ul>\n<li>Valid<\/li>\n<li>Risky<\/li>\n<li>Unknown<\/li>\n<li>Invalid<\/li>\n<\/ul>\n<p>In a signup flow, the API should be called server-side during or just after form submission (ideally on field blur for real-time UX).<\/p>\n<p>The correct implementation always includes:<\/p>\n<ul>\n<li>1\u20132 second timeout fallback<\/li>\n<li>Soft acceptance for uncertain results<\/li>\n<li>UX mapping based on status tier, not raw technical errors<\/li>\n<\/ul>\n<p>Most failed implementations break here by treating all non-valid responses as hard failures.<\/p>\n<\/div>\n<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_84 counter-hierarchy ez-toc-counter ez-toc-custom ez-toc-container-direction\">\n<div class=\"ez-toc-title-container\">\n<p class=\"ez-toc-title\" style=\"cursor:inherit\">Table of Contents<\/p>\n<span class=\"ez-toc-title-toggle\"><\/span><\/div>\n<nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/www.emailverify.io\/blog\/email-verification-api-guide\/#what-an-email-verification-api-actually-does\" >What an Email Verification API Actually Does?<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/www.emailverify.io\/blog\/email-verification-api-guide\/#email-verification-api-response-fields-status-and-signals\" >Email Verification API Response (Fields, Status, and Signals)<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/www.emailverify.io\/blog\/email-verification-api-guide\/#when-to-call-email-verification-api-in-a-signup-flow\" >When to Call Email Verification API in a Signup Flow<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/www.emailverify.io\/blog\/email-verification-api-guide\/#how-to-use-debouncing-for-email-verification\" >How to Use Debouncing for Email Verification<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/www.emailverify.io\/blog\/email-verification-api-guide\/#should-you-verify-emails-server-side-or-client-side\" >Should You Verify Emails Server-Side or Client-Side?<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/www.emailverify.io\/blog\/email-verification-api-guide\/#code-python-flask\" >Code: Python (Flask)<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-7\" href=\"https:\/\/www.emailverify.io\/blog\/email-verification-api-guide\/#code-nodejs-express\" >Code: Node.js (Express)<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-8\" href=\"https:\/\/www.emailverify.io\/blog\/email-verification-api-guide\/#code-php\" >Code: PHP<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-9\" href=\"https:\/\/www.emailverify.io\/blog\/email-verification-api-guide\/#timeout-and-fallback-strategy\" >Timeout and Fallback Strategy<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-10\" href=\"https:\/\/www.emailverify.io\/blog\/email-verification-api-guide\/#email-verification-ux-what-to-show-users-for-each-status\" >Email Verification UX: What to Show Users for Each Status<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-11\" href=\"https:\/\/www.emailverify.io\/blog\/email-verification-api-guide\/#how-to-handle-risky-and-unknown-statuses\" >How to Handle Risky and Unknown Statuses<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-12\" href=\"https:\/\/www.emailverify.io\/blog\/email-verification-api-guide\/#how-should-you-cache-email-verification-results\" >How Should You Cache Email Verification Results?<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-13\" href=\"https:\/\/www.emailverify.io\/blog\/email-verification-api-guide\/#how-do-you-implement-rate-limiting-for-email-verification-apis\" >How Do You Implement Rate Limiting for Email Verification APIs?<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-14\" href=\"https:\/\/www.emailverify.io\/blog\/email-verification-api-guide\/#common-implementation-mistakes\" >Common Implementation Mistakes<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-15\" href=\"https:\/\/www.emailverify.io\/blog\/email-verification-api-guide\/#how-do-you-test-an-email-verification-api-integration\" >How Do You Test an Email Verification API Integration?<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-16\" href=\"https:\/\/www.emailverify.io\/blog\/email-verification-api-guide\/#how-does-emailverifyio-support-this-pattern\" >How Does EmailVerify.io Support This Pattern?<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-17\" href=\"https:\/\/www.emailverify.io\/blog\/email-verification-api-guide\/#frequently-asked-questions\" >Frequently Asked Questions<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-18\" href=\"https:\/\/www.emailverify.io\/blog\/email-verification-api-guide\/#final-thoughts\" >Final Thoughts<\/a><\/li><\/ul><\/nav><\/div>\n<h2><span class=\"ez-toc-section\" id=\"what-an-email-verification-api-actually-does\"><\/span>What an Email Verification API Actually Does?<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>An email verification API is a structured abstraction over a multi-stage validation pipeline. When you send an email address, it typically executes the following:<\/p>\n<ul>\n<li>Syntax validation<\/li>\n<li>Domain resolution (<a href=\"https:\/\/www.emailverify.io\/blog\/dns-records-for-email\/\" target=\"_blank\" rel=\"noopener\">DNS records lookup<\/a>)<\/li>\n<li>MX record verification<\/li>\n<li>SMTP handshake with mail server<\/li>\n<li>Risk classification (catch-all, role-based, disposable detection)<\/li>\n<\/ul>\n<p>Each stage contributes to a final classification rather than acting independently.<\/p>\n<p>The key engineering detail is that SMTP probing introduces latency variance. Modern APIs handle this with connection reuse, retries, and provider-level optimizations so that responses stay consistent in sub-second ranges under normal conditions.<\/p>\n<div class=\"info-box box-blue\">\n<div class=\"box-label\">Key Insight<\/div>\n<p>The integration question isn\u2019t really \u201chow do I call the API.\u201d That\u2019s an HTTP request, and any language can make one. The question is what to do with the response. Verifiers return graded confidence (Valid, Risky, Unknown, Invalid), and the difference between a good integration and a bad one is how it handles each tier. Most of this article is about that.<\/p>\n<\/div>\n<h2><span class=\"ez-toc-section\" id=\"email-verification-api-response-fields-status-and-signals\"><\/span>Email Verification API Response (Fields, Status, and Signals)<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Most verification APIs return JSON with the same broad structure: a primary status, a reason code that explains it, and a set of underlying signals.<\/p>\n<p>Here&#8217;s what a typical EmailVerify.io response looks like:<\/p>\n<div class=\"code-terminal-box\">\n<div class=\"code-label\">Verification API response (illustrative):<\/div>\n<div class=\"code-content\">\n<div>{<\/div>\n<div>&#8220;email&#8221;: &#8220;jane@example.com&#8221;,<\/div>\n<div>&#8220;status&#8221;: &#8220;valid&#8221;,<\/div>\n<div>&#8220;reason&#8221;: &#8220;smtp_accepted&#8221;,<\/div>\n<div>&#8220;score&#8221;: 0.97,<\/div>\n<div>&#8220;signals&#8221;: {<\/div>\n<div>&#8220;syntax_valid&#8221;: true,<\/div>\n<div>&#8220;domain_resolves&#8221;: true,<\/div>\n<div>&#8220;mx_present&#8221;: true,<\/div>\n<div>&#8220;smtp_response&#8221;: &#8220;250&#8221;,<\/div>\n<div>&#8220;is_catch_all&#8221;: false,<\/div>\n<div>&#8220;is_role&#8221;: false,<\/div>\n<div>&#8220;is_disposable&#8221;: false,<\/div>\n<div>&#8220;is_free_provider&#8221;: false<\/div>\n<div>},<\/div>\n<div>&#8220;provider&#8221;: &#8220;google_workspace&#8221;,<\/div>\n<div>&#8220;checked_at&#8221;: &#8220;2026-04-30T12:00:00Z&#8221;<\/div>\n<div>}<\/div>\n<\/div>\n<\/div>\n<p>The fields that matter for your integration logic:<\/p>\n\n<table id=\"tablepress-125\" class=\"tablepress tablepress-id-125\">\n<thead>\n<tr class=\"row-1\">\n\t<th class=\"column-1\"><span style=\"color:#FFFFFF;\"><strong>Field<\/strong><\/span><\/th><th class=\"column-2\"><span style=\"color:#FFFFFF;\"><strong>Why It Matters<\/strong><\/span><\/th>\n<\/tr>\n<\/thead>\n<tbody class=\"row-striping row-hover\">\n<tr class=\"row-2\">\n\t<td class=\"column-1\"><span style=\"color:#1F2D3D;\"><strong>status<\/strong><\/span><\/td><td class=\"column-2\"><span style=\"color:#333333;\">The primary decision input. Branch on this first.<\/span><\/td>\n<\/tr>\n<tr class=\"row-3\">\n\t<td class=\"column-1\"><span style=\"color:#1F2D3D;\"><strong>reason<\/strong><\/span><\/td><td class=\"column-2\"><span style=\"color:#333333;\">Use to differentiate between Risky and Unknown (catch_all vs role vs disposable, etc.).<\/span><\/td>\n<\/tr>\n<tr class=\"row-4\">\n\t<td class=\"column-1\"><span style=\"color:#1F2D3D;\"><strong>score<\/strong><\/span><\/td><td class=\"column-2\"><span style=\"color:#333333;\">Numeric confidence, useful when you want a threshold rather than a categorical decision.<\/span><\/td>\n<\/tr>\n<tr class=\"row-5\">\n\t<td class=\"column-1\"><span style=\"color:#1F2D3D;\"><strong>signals<\/strong><\/span><\/td><td class=\"column-2\"><span style=\"color:#333333;\">Detailed flags. Useful for storing alongside the contact record.<\/span><\/td>\n<\/tr>\n<tr class=\"row-6\">\n\t<td class=\"column-1\"><span style=\"color:#1F2D3D;\"><strong>provider<\/strong><\/span><\/td><td class=\"column-2\"><span style=\"color:#333333;\">Hosting platform of the recipient (Google, Microsoft, etc.). Useful for later analytics.<\/span><\/td>\n<\/tr>\n<tr class=\"row-7\">\n\t<td class=\"column-1\"><span style=\"color:#1F2D3D;\"><strong>checked_at<\/strong><\/span><\/td><td class=\"column-2\"><span style=\"color:#333333;\">Timestamp. Useful for cache invalidation.<\/span><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<!-- #tablepress-125 from cache -->\n<p>Different vendors will use slightly different field names, but the shape is the same. The four-status pattern (Valid, Risky, Unknown, Invalid) is the de facto industry standard.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"when-to-call-email-verification-api-in-a-signup-flow\"><\/span>When to Call Email Verification API in a Signup Flow<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>There are three reasonable places to fire the verification call in a signup flow, and they&#8217;re all valid. The right choice depends on whether you want instant feedback, friction-free submission, or both.<\/p>\n<h3>Option A: On-Field Blur<\/h3>\n<p>Fire the API call when the email input loses focus (the user clicks away from it). This is the right default for most flows and the core principle behind any <a href=\"https:\/\/www.emailverify.io\/blog\/why-to-use-real-time-email-checker\/\" target=\"_blank\" rel=\"noopener\">real-time email checker<\/a>. The user has finished typing, the request goes off in the background, and by the time they click submit, the result is usually back. The submit-button experience feels instant.<\/p>\n<h3>Option B: On Form Submit<\/h3>\n<p>Fire the API call when the user clicks submit. Simpler to implement, but the user feels the latency directly. With a fast API and a sensible timeout, this is fine for low-volume forms; for anything user-facing in a competitive market, blur is better.<\/p>\n<h3>Option C: While Typing (Debounced)<\/h3>\n<p>Fire the API call after a short delay following each keystroke, canceling previous calls. Useful when you want to surface typo suggestions in real time (&#8220;Did you mean &#8230;@gmail.com?&#8221;). Adds complexity and cost, since you can fire several requests per signup, but the UX is the smoothest. Always combine with debouncing (covered in the next section) so you don&#8217;t burn API credits on every keystroke.<\/p>\n\n<table id=\"tablepress-124\" class=\"tablepress tablepress-id-124\">\n<thead>\n<tr class=\"row-1\">\n\t<th class=\"column-1\"><span style=\"color:#FFFFFF;\"><strong>Trigger<\/strong><\/span><\/th><th class=\"column-2\"><span style=\"color:#FFFFFF;\"><strong>Best For<\/strong><\/span><\/th><th class=\"column-3\"><span style=\"color:#FFFFFF;\"><strong>Trade-off<\/strong><\/span><\/th>\n<\/tr>\n<\/thead>\n<tbody class=\"row-striping row-hover\">\n<tr class=\"row-2\">\n\t<td class=\"column-1\"><span style=\"color:#1F2D3D;\"><strong>On field blur (default)<\/strong><\/span><\/td><td class=\"column-2\"><span style=\"color:#333333;\">Most signup forms. Submit feels instant.<\/span><\/td><td class=\"column-3\"><span style=\"color:#333333;\">Slightly more complex than on-submit.<\/span><\/td>\n<\/tr>\n<tr class=\"row-3\">\n\t<td class=\"column-1\"><span style=\"color:#1F2D3D;\"><strong>On form submit<\/strong><\/span><\/td><td class=\"column-2\"><span style=\"color:#333333;\">Low-volume forms; back-office tools.<\/span><\/td><td class=\"column-3\"><span style=\"color:#333333;\">User feels the latency directly.<\/span><\/td>\n<\/tr>\n<tr class=\"row-4\">\n\t<td class=\"column-1\"><span style=\"color:#1F2D3D;\"><strong>On typing (debounced)<\/strong><\/span><\/td><td class=\"column-2\"><span style=\"color:#333333;\">High-conversion flows where typo suggestions matter.<\/span><\/td><td class=\"column-3\"><span style=\"color:#333333;\">More API calls per signup; higher cost.<\/span><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<!-- #tablepress-124 from cache -->\n<div class=\"info-box box-blue\">\n<div class=\"box-label\">Expert Tip<\/div>\n<p>If you\u2019re unsure which trigger to use, start with on-blur. It hits the sweet spot of cost, complexity, and UX for almost every form. You can layer on typo suggestions later if conversion data shows users would benefit from real-time correction.<\/p>\n<\/div>\n<h2><span class=\"ez-toc-section\" id=\"how-to-use-debouncing-for-email-verification\"><\/span>How to Use Debouncing for Email Verification<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>If you verify emails during typing, debouncing is mandatory. Without it, every keystroke fires a new API request, you burn through credits, and you end up rate-limited within the first few signups. Debouncing waits a short delay after the last keystroke before firing and cancels any prior pending call.<\/p>\n<p>An ideal debounce window is 400 to 800 milliseconds. Long enough that users finish typing the local part before the call fires; short enough that the user doesn&#8217;t notice the delay.<\/p>\n<div class=\"code-terminal-box\">\n<div class=\"code-label\">JavaScript debounce, vanilla:<\/div>\n<div class=\"code-content\">\n<div>function debounce(fn, delay) {<\/div>\n<div>let timer;<\/div>\n<div>return (&#8230;args) =&gt; {<\/div>\n<div>clearTimeout(timer);<\/div>\n<div>timer = setTimeout(() =&gt; fn(&#8230;args), delay);<\/div>\n<div>};<\/div>\n<div>}<\/div>\n<div><\/div>\n<div>const verifyEmail = async (email) =&gt; {<\/div>\n<div>const res = await fetch(&#8216;\/api\/verify-email&#8217;, {<\/div>\n<div>method: &#8216;POST&#8217;,<\/div>\n<div>headers: { &#8216;Content-Type&#8217;: &#8216;application\/json&#8217; },<\/div>\n<div>body: JSON.stringify({ email })<\/div>\n<div>});<\/div>\n<div>return res.json();<\/div>\n<div>};<\/div>\n<div><\/div>\n<div>const debouncedVerify = debounce(verifyEmail, 600);<\/div>\n<div><\/div>\n<div>emailInput.addEventListener(&#8216;input&#8217;, (e) =&gt; {<\/div>\n<div>debouncedVerify(e.target.value);<\/div>\n<div>});<\/div>\n<\/div>\n<\/div>\n<div class=\"info-box box-red\">\n<div class=\"box-label\">Common Mistake<\/div>\n<p>Calling the verification API on every keystroke without debouncing. We\u2019ve seen forms make 30+ API calls per signup because the developer wired the call to onChange without a delay. The cost runs up quickly, the API rate-limits, and the user gets a flicker of changing statuses for partial addresses that haven\u2019t finished typing.<\/p>\n<\/div>\n<h2><span class=\"ez-toc-section\" id=\"should-you-verify-emails-server-side-or-client-side\"><\/span>Should You Verify Emails Server-Side or Client-Side?<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>This is the most common architectural question. The answer is server-side, and the reason is your API key.<\/p>\n<p>If you call the verification API directly from client-side JavaScript, your API key is in the page source where any browser can see it. A determined visitor extracts it, and now they have your credentials. They can verify their own addresses on your bill, share the key, or use it for purposes you didn&#8217;t authorize. The cost (and the abuse) is yours.<\/p>\n<p>The right pattern is to expose your own API endpoint (something like \/api\/verify-email) on your application server, which forwards the call to the verification API with your secret key, then returns the result to the client. The client never sees the key, and you can add your own rate limiting, logging, and abuse handling around the call.<\/p>\n<div class=\"code-terminal-box\">\n<div class=\"code-label\">Architecture Diagram:<\/div>\n<div class=\"code-content\">\n<div>Browser Your Server Verifier API<\/div>\n<div>&#8212;&#8212;- &#8212;&#8212;&#8212;&#8211; &#8212;&#8212;&#8212;&#8212;<\/div>\n<div>POST \/api\/verify-email<\/div>\n<div>(no API key) &#8211;&gt;<\/div>\n<div>POST https:\/\/api.verifier.com\/verify<\/div>\n<div>Authorization: Bearer SECRET_KEY &#8211;&gt;<\/div>\n<div><\/div>\n<div>&lt;&#8211; { status, reason, &#8230; }<\/div>\n<div>&lt;&#8211; { status, reason, &#8230; }<\/div>\n<\/div>\n<\/div>\n<div class=\"info-box box-blue\">\n<div class=\"box-label\">Key Insight<\/div>\n<p>There\u2019s exactly one valid scenario for client-side verification calls: a publishable \/ restricted-domain key designed for that use, where the vendor enforces origin restrictions on their side. EmailVerify.io and most verifiers don\u2019t offer this; if yours does, the docs will be explicit about it. Default to server-side unless the vendor specifically says otherwise.<\/p>\n<\/div>\n<h2><span class=\"ez-toc-section\" id=\"code-python-flask\"><\/span>Code: Python (Flask)<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Here&#8217;s a complete Flask endpoint that wraps the EmailVerify.io API. It accepts an email from the client, calls the verification API server-side, handles errors and timeouts, and returns the result to the client.<\/p>\n<div class=\"code-terminal-box\">\n<div class=\"code-label\">Python (Flask) \u2014 server endpoint:<\/div>\n<div class=\"code-content\">\n<div>import os<\/div>\n<div>import requests<\/div>\n<div>from flask import Flask, request, jsonify<\/div>\n<div><\/div>\n<div>app = Flask(__name__)<\/div>\n<div>API_KEY = os.environ[&#8216;EMAILVERIFY_API_KEY&#8217;]<\/div>\n<div>API_URL = &#8216;https:\/\/api.emailverify.io\/v1\/verify&#8217;<\/div>\n<div><\/div>\n<div>@app.route(&#8216;\/api\/verify-email&#8217;, methods=[&#8216;POST&#8217;])<\/div>\n<div>def verify_email():<\/div>\n<div>data = request.get_json() or {}<\/div>\n<div>email = (data.get(&#8217;email&#8217;) or &#8221;).strip().lower()<\/div>\n<div><\/div>\n<div>if not email or &#8216;@&#8217; not in email:<\/div>\n<div>return jsonify({<\/div>\n<div>&#8216;status&#8217;: &#8216;invalid&#8217;,<\/div>\n<div>&#8216;reason&#8217;: &#8216;invalid_syntax&#8217;,<\/div>\n<div>}), 200<\/div>\n<div><\/div>\n<div>try:<\/div>\n<div>resp = requests.post(<\/div>\n<div>API_URL,<\/div>\n<div>headers={&#8216;Authorization&#8217;: f&#8217;Bearer {API_KEY}&#8217;},<\/div>\n<div>json={&#8217;email&#8217;: email},<\/div>\n<div>timeout=2.0,<\/div>\n<div>)<\/div>\n<div>resp.raise_for_status()<\/div>\n<div>result = resp.json()<\/div>\n<div>return jsonify({<\/div>\n<div>&#8216;status&#8217;: result[&#8216;status&#8217;],<\/div>\n<div>&#8216;reason&#8217;: result.get(&#8216;reason&#8217;),<\/div>\n<div>&#8216;score&#8217;: result.get(&#8216;score&#8217;),<\/div>\n<div>}), 200<\/div>\n<div><\/div>\n<div>except requests.Timeout:<\/div>\n<div>return jsonify({<\/div>\n<div>&#8216;status&#8217;: &#8216;unknown&#8217;,<\/div>\n<div>&#8216;reason&#8217;: &#8216;verifier_timeout&#8217;,<\/div>\n<div>&#8216;soft_accept&#8217;: True,<\/div>\n<div>}), 200<\/div>\n<div><\/div>\n<div>except requests.RequestException:<\/div>\n<div>return jsonify({<\/div>\n<div>&#8216;status&#8217;: &#8216;unknown&#8217;,<\/div>\n<div>&#8216;reason&#8217;: &#8216;verifier_error&#8217;,<\/div>\n<div>&#8216;soft_accept&#8217;: True,<\/div>\n<div>}), 200<\/div>\n<\/div>\n<\/div>\n<h2><span class=\"ez-toc-section\" id=\"code-nodejs-express\"><\/span>Code: Node.js (Express)<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Same logic in Node.js with Express and the built-in fetch (Node 18+). Drop this into your existing Express app and wire the route into the form.<\/p>\n<div class=\"code-terminal-box\">\n<div class=\"code-label\">Node.js (Express) \u2014 server endpoint:<\/div>\n<div class=\"code-content\">\n<div>import express from &#8216;express&#8217;;<\/div>\n<div><\/div>\n<div>const app = express();<\/div>\n<div>app.use(express.json());<\/div>\n<div><\/div>\n<div>const API_KEY = process.env.EMAILVERIFY_API_KEY;<\/div>\n<div>const API_URL = &#8216;https:\/\/api.emailverify.io\/v1\/verify&#8217;;<\/div>\n<div><\/div>\n<div>app.post(&#8216;\/api\/verify-email&#8217;, async (req, res) =&gt; {<\/div>\n<div>const email = (req.body?.email || &#8221;).trim().toLowerCase();<\/div>\n<div><\/div>\n<div>if (!email || !email.includes(&#8216;@&#8217;)) {<\/div>\n<div>return res.json({<\/div>\n<div>status: &#8216;invalid&#8217;,<\/div>\n<div>reason: &#8216;invalid_syntax&#8217;,<\/div>\n<div>});<\/div>\n<div>}<\/div>\n<div><\/div>\n<div>const controller = new AbortController();<\/div>\n<div>const timeoutId = setTimeout(() =&gt; controller.abort(), 2000);<\/div>\n<div><\/div>\n<div>try {<\/div>\n<div>const apiRes = await fetch(API_URL, {<\/div>\n<div>method: &#8216;POST&#8217;,<\/div>\n<div>headers: {<\/div>\n<div>&#8216;Authorization&#8217;: `Bearer ${API_KEY}`,<\/div>\n<div>&#8216;Content-Type&#8217;: &#8216;application\/json&#8217;,<\/div>\n<div>},<\/div>\n<div>body: JSON.stringify({ email }),<\/div>\n<div>signal: controller.signal,<\/div>\n<div>});<\/div>\n<div>clearTimeout(timeoutId);<\/div>\n<div><\/div>\n<div>if (!apiRes.ok) throw new Error(`API ${apiRes.status}`);<\/div>\n<div>const data = await apiRes.json();<\/div>\n<div><\/div>\n<div>return res.json({<\/div>\n<div>status: data.status,<\/div>\n<div>reason: data.reason,<\/div>\n<div>score: data.score,<\/div>\n<div>});<\/div>\n<div>} catch (err) {<\/div>\n<div>clearTimeout(timeoutId);<\/div>\n<div>return res.json({<\/div>\n<div>status: &#8216;unknown&#8217;,<\/div>\n<div>reason: err.name === &#8216;AbortError&#8217; ? &#8216;verifier_timeout&#8217; : &#8216;verifier_error&#8217;,<\/div>\n<div>soft_accept: true,<\/div>\n<div>});<\/div>\n<div>}<\/div>\n<div>});<\/div>\n<div><\/div>\n<div>app.listen(3000);<\/div>\n<\/div>\n<\/div>\n<h2><span class=\"ez-toc-section\" id=\"code-php\"><\/span>Code: PHP<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>PHP version using cURL, suitable for any framework or vanilla setup. The pattern is identical to the Python and Node versions: server-side call, timeout, soft-accept on failure.<\/p>\n<div class=\"code-terminal-box\">\n<div class=\"code-label\">PHP \u2014 server endpoint:<\/div>\n<div class=\"code-content\">\n<div>&lt;?php<\/div>\n<div>header(&#8216;Content-Type: application\/json&#8217;);<\/div>\n<div><\/div>\n<div>$body = json_decode(file_get_contents(&#8216;php:\/\/input&#8217;), true) ?? [];<\/div>\n<div>$email = strtolower(trim($body[&#8217;email&#8217;] ?? &#8221;));<\/div>\n<div><\/div>\n<div>if (!$email || !str_contains($email, &#8216;@&#8217;)) {<\/div>\n<div>echo json_encode([<\/div>\n<div>&#8216;status&#8217; =&gt; &#8216;invalid&#8217;,<\/div>\n<div>&#8216;reason&#8217; =&gt; &#8216;invalid_syntax&#8217;,<\/div>\n<div>]);<\/div>\n<div>exit;<\/div>\n<div>}<\/div>\n<div><\/div>\n<div>$apiKey = getenv(&#8216;EMAILVERIFY_API_KEY&#8217;);<\/div>\n<div>$apiUrl = &#8216;https:\/\/api.emailverify.io\/v1\/verify&#8217;;<\/div>\n<div><\/div>\n<div>$ch = curl_init($apiUrl);<\/div>\n<div>curl_setopt_array($ch, [<\/div>\n<div>CURLOPT_POST =&gt; true,<\/div>\n<div>CURLOPT_RETURNTRANSFER =&gt; true,<\/div>\n<div>CURLOPT_TIMEOUT_MS =&gt; 2000,<\/div>\n<div>CURLOPT_HTTPHEADER =&gt; [<\/div>\n<div>&#8220;Authorization: Bearer {$apiKey}&#8221;,<\/div>\n<div>&#8216;Content-Type: application\/json&#8217;,<\/div>\n<div>],<\/div>\n<div>CURLOPT_POSTFIELDS =&gt; json_encode([&#8217;email&#8217; =&gt; $email]),<\/div>\n<div>]);<\/div>\n<div><\/div>\n<div>$response = curl_exec($ch);<\/div>\n<div>$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);<\/div>\n<div>$err = curl_errno($ch);<\/div>\n<div>curl_close($ch);<\/div>\n<div><\/div>\n<div>if ($err || $httpCode !== 200) {<\/div>\n<div>echo json_encode([<\/div>\n<div>&#8216;status&#8217; =&gt; &#8216;unknown&#8217;,<\/div>\n<div>&#8216;reason&#8217; =&gt; $err === CURLE_OPERATION_TIMEDOUT ? &#8216;verifier_timeout&#8217; : &#8216;verifier_error&#8217;,<\/div>\n<div>&#8216;soft_accept&#8217; =&gt; true,<\/div>\n<div>]);<\/div>\n<div>exit;<\/div>\n<div>}<\/div>\n<div><\/div>\n<div>$data = json_decode($response, true);<\/div>\n<div>echo json_encode([<\/div>\n<div>&#8216;status&#8217; =&gt; $data[&#8216;status&#8217;] ?? &#8216;unknown&#8217;,<\/div>\n<div>&#8216;reason&#8217; =&gt; $data[&#8216;reason&#8217;] ?? null,<\/div>\n<div>&#8216;score&#8217; =&gt; $data[&#8216;score&#8217;] ?? null,<\/div>\n<div>]);<\/div>\n<\/div>\n<\/div>\n<h2><span class=\"ez-toc-section\" id=\"timeout-and-fallback-strategy\"><\/span>Timeout and Fallback Strategy<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>The single most important thing your integration does is handle the case where the verifier doesn&#8217;t respond fast enough. Without a timeout fallback, a slow API call can block your signup form, fail every signup attempt during an outage, and turn your verifier into a single point of failure for new user acquisition.<\/p>\n<p>The right pattern is a short timeout, a soft accept on timeout, and a flag for a later bulk recheck.<\/p>\n<p>Specifically:<\/p>\n<ul>\n<li>Set the timeout to 1\u20132 seconds. Anything longer means the user notices.<\/li>\n<li>On timeout, return a status of \u201cunknown\u201d with reason \u201cverifier_timeout.\u201d<\/li>\n<li>In your application logic, treat verifier_timeout as a soft-accept: let the signup proceed, but tag the contact record so a <a href=\"https:\/\/www.emailverify.io\/blog\/blog-bulk-email-verification\/\" target=\"_blank\" rel=\"noopener\">bulk email verification<\/a> run can revisit later.<\/li>\n<li>Log the timeout for monitoring. A sudden spike usually means the API is having a bad moment, not that your code is broken.<\/li>\n<\/ul>\n<p>This pattern is the difference between a verifier that prevents bad data and a verifier that prevents legitimate signups. The first is what you want; the second is a self-inflicted incident.<\/p>\n<div class=\"info-box box-blue\">\n<div class=\"box-label\">Expert Tip<\/div>\n<p>If you ever see a spike in verifier_timeout reasons in your logs, don\u2019t panic. The timeout fallback is doing exactly what it should. The next step is check your verifier provider\u2019s status page, and if the issue persists, run a bulk pass over the soft-accepted contacts once the API returns to normal latency. None of those signups are lost; they\u2019re just queued for re-verification.<\/p>\n<\/div>\n<h2><span class=\"ez-toc-section\" id=\"email-verification-ux-what-to-show-users-for-each-status\"><\/span>Email Verification UX: What to Show Users for Each Status<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>This is where most signup integrations fail, not in the API call itself, but in how the results are translated into user-facing behavior.<\/p>\n<p>Email verification APIs don\u2019t just return \u201cvalid or invalid.\u201d In production systems like EmailVerify.io, results are more nuanced and designed to reflect real-world email behavior.<\/p>\n<p>The correct UX strategy is to map each status to a clear action: accept, warn, block, or defer, without overloading users with technical details.<\/p>\n\n<table id=\"tablepress-123\" class=\"tablepress tablepress-id-123\">\n<thead>\n<tr class=\"row-1\">\n\t<th class=\"column-1\"><strong>API Status<\/strong><\/th><th class=\"column-2\"><strong>Meaning<\/strong><\/th><th class=\"column-3\"><strong>Recommended Action<\/strong><\/th><th class=\"column-4\"><strong>User Experience<\/strong><\/th>\n<\/tr>\n<\/thead>\n<tbody class=\"row-striping row-hover\">\n<tr class=\"row-2\">\n\t<td class=\"column-1\"><strong>Valid<\/strong><\/td><td class=\"column-2\">Email is safe and deliverable<\/td><td class=\"column-3\">Accept<\/td><td class=\"column-4\">Proceed silently<\/td>\n<\/tr>\n<tr class=\"row-3\">\n\t<td class=\"column-1\"><strong>Invalid<\/strong><\/td><td class=\"column-2\">Email cannot receive mail (bad syntax, no mailbox, etc.)<\/td><td class=\"column-3\">Block<\/td><td class=\"column-4\">Ask user to correct the email.<\/td>\n<\/tr>\n<tr class=\"row-4\">\n\t<td class=\"column-1\"><strong>Catch-all<\/strong><\/td><td class=\"column-2\">The domain accepts all emails but mailbox validity is unclear<\/td><td class=\"column-3\">Accept<\/td><td class=\"column-4\">No message (silent accept)<\/td>\n<\/tr>\n<tr class=\"row-5\">\n\t<td class=\"column-1\"><strong>Do-not-mail<\/strong><\/td><td class=\"column-2\">High-risk or suppressed address (spam traps, abuse, or restricted)<\/td><td class=\"column-3\">Block<\/td><td class=\"column-4\">Prevent signup<\/td>\n<\/tr>\n<tr class=\"row-6\">\n\t<td class=\"column-1\"><strong>Role-based<\/strong><\/td><td class=\"column-2\">Shared inbox (info@, support@, admin@)<\/td><td class=\"column-3\">Soft warn<\/td><td class=\"column-4\">Suggest personal email<\/td>\n<\/tr>\n<tr class=\"row-7\">\n\t<td class=\"column-1\"><strong>Unknown<\/strong><\/td><td class=\"column-2\">Verification could not be completed (temporary failure, greylisting, etc.)<\/td><td class=\"column-3\">Accept (soft)<\/td><td class=\"column-4\">Proceed and recheck later<\/td>\n<\/tr>\n<tr class=\"row-8\">\n\t<td class=\"column-1\"><strong>Skipped<\/strong><\/td><td class=\"column-2\">Verification bypassed due to system rules or limits<\/td><td class=\"column-3\">Accept<\/td><td class=\"column-4\">No message<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<!-- #tablepress-123 from cache -->\n<ul>\n<li><strong>Valid:<\/strong> Email is safe and deliverable. Action: Accept. Message: None.<\/li>\n<li><strong>Risky (Catch-all):<\/strong> Domain accepts all mail but specific mailbox is uncertain. Action: Accept (silently). Message: None.<\/li>\n<li><strong>Risky (Role-based):<\/strong> Shared\/distribution mailbox (info@, support@, etc). Action: Accept (optional soft-warn). Message: &#8220;Is this your personal email?&#8221;<\/li>\n<li><strong>Unknown:<\/strong> Verification could not be completed (timeout, greylisting). Action: Accept (soft) and flag for bulk recheck. Message: None.<\/li>\n<li><strong>Invalid:<\/strong> Mailbox does not exist or domain cannot receive mail. Action: Block. Message: &#8220;Please check for typos.&#8221;<\/li>\n<\/ul>\n<div class=\"info-box box-red\">\n<div class=\"box-label\">Common Mistake<\/div>\n<p>Treating every invalid status as a hard block. Users who type a perfectly valid email at a <a href=\"https:\/\/www.emailverify.io\/blog\/catch-all-emails\/\" target=\"_blank\" rel=\"noopener\">catch-all<\/a> domain (which is most small businesses and many enterprise addresses) will hit a wall they can\u2019t solve, and your signup conversion drops measurably. The honest move is to accept catch-all addresses silently and let engagement data determine whether the mailbox is real over time.<\/p>\n<\/div>\n<h2><span class=\"ez-toc-section\" id=\"how-to-handle-risky-and-unknown-statuses\"><\/span>How to Handle Risky and Unknown Statuses<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Risky and Unknown deserve their own section because they&#8217;re where most teams get the integration wrong. They&#8217;re not the same status, they don&#8217;t have the same cause, and they shouldn&#8217;t be handled the same way.<\/p>\n<h3>Risky Addresses<\/h3>\n<p>&#8220;Risky&#8221; means the verifier got a response, but the response is ambiguous. The most common reasons are catch-all, role-based, disposable, or anti-probe behavior at major providers (Yahoo, AOL, and certain Microsoft tenants).<\/p>\n<p>The right response to Risky depends on the reason code.<\/p>\n<ul>\n<li><a href=\"https:\/\/www.emailverify.io\/blog\/catch-all-emails\/\" target=\"_blank\" rel=\"noopener\">Catch-all emails<\/a> almost always means the signup should proceed because legitimate small-business addresses are catch-all, and you can&#8217;t filter on this without losing customers.<\/li>\n<li><a href=\"https:\/\/www.emailverify.io\/blog\/disposable-emails\/\" target=\"_blank\" rel=\"noopener\">Disposable emails<\/a> usually means block, because disposable mailboxes don&#8217;t represent real users.<\/li>\n<li><a href=\"https:\/\/www.emailverify.io\/blog\/role-based-emails\/\" target=\"_blank\" rel=\"noopener\">Role-based emails<\/a> usually means &#8220;accept with a soft warning.&#8221;<\/li>\n<li>Anti-probe usually means accept (the underlying mailbox is probably real; the verifier just couldn&#8217;t get a clean answer).<\/li>\n<\/ul>\n<h3>Unknown Addresses<\/h3>\n<p>Unknown means the verifier couldn&#8217;t get a meaningful response at all, usually because of a timeout, greylisting, or temporary server unavailability. This isn&#8217;t an address problem; it&#8217;s a verification problem. The right response is almost always to soft-accept the signup, tag the contact for later bulk verification, and move on.<\/p>\n<p>Treating &#8220;Unknown&#8221; as &#8220;Invalid&#8221; is a self-inflicted wound. Most unknown addresses turn out to be valid on the next try. A signup form that blocks them is blocking real users on the verifier&#8217;s bad day.<\/p>\n\n<table id=\"tablepress-122\" class=\"tablepress tablepress-id-122\">\n<thead>\n<tr class=\"row-1\">\n\t<th class=\"column-1\"><span style=\"color:#FFFFFF;\"><strong>Reason code<\/strong><\/span><\/th><th class=\"column-2\"><span style=\"color:#FFFFFF;\"><strong>Status<\/strong><\/span><\/th><th class=\"column-3\"><span style=\"color:#FFFFFF;\"><strong>Default action<\/strong><\/span><\/th><th class=\"column-4\"><span style=\"color:#FFFFFF;\"><strong>Why<\/strong><\/span><\/th>\n<\/tr>\n<\/thead>\n<tbody class=\"row-striping row-hover\">\n<tr class=\"row-2\">\n\t<td class=\"column-1\"><span style=\"color:#1F2D3D;\"><strong>catch_all<\/strong><\/span><\/td><td class=\"column-2\"><span style=\"color:#333333;\">Risky<\/span><\/td><td class=\"column-3\"><span style=\"color:#333333;\">Accept<\/span><\/td><td class=\"column-4\"><span style=\"color:#333333;\">Legitimate addresses; can\u2019t filter without losing real users.<\/span><\/td>\n<\/tr>\n<tr class=\"row-3\">\n\t<td class=\"column-1\"><span style=\"color:#1F2D3D;\"><strong>role_based<\/strong><\/span><\/td><td class=\"column-2\"><span style=\"color:#333333;\">Risky<\/span><\/td><td class=\"column-3\"><span style=\"color:#333333;\">Accept with soft warn<\/span><\/td><td class=\"column-4\"><span style=\"color:#333333;\">Real but lower-quality engagement.<\/span><\/td>\n<\/tr>\n<tr class=\"row-4\">\n\t<td class=\"column-1\"><span style=\"color:#1F2D3D;\"><strong>disposable<\/strong><\/span><\/td><td class=\"column-2\"><span style=\"color:#333333;\">Risky<\/span><\/td><td class=\"column-3\"><span style=\"color:#333333;\">Block<\/span><\/td><td class=\"column-4\"><span style=\"color:#333333;\">Almost never represents a real user.<\/span><\/td>\n<\/tr>\n<tr class=\"row-5\">\n\t<td class=\"column-1\"><span style=\"color:#1F2D3D;\"><strong>free_provider<\/strong><\/span><\/td><td class=\"column-2\"><span style=\"color:#333333;\">Risky<\/span><\/td><td class=\"column-3\"><span style=\"color:#333333;\">Accept<\/span><\/td><td class=\"column-4\"><span style=\"color:#333333;\">Gmail\/Yahoo\/Outlook are mostly real users.<\/span><\/td>\n<\/tr>\n<tr class=\"row-6\">\n\t<td class=\"column-1\"><span style=\"color:#1F2D3D;\"><strong>anti_probe_provider<\/strong><\/span><\/td><td class=\"column-2\"><span style=\"color:#333333;\">Risky<\/span><\/td><td class=\"column-3\"><span style=\"color:#333333;\">Accept<\/span><\/td><td class=\"column-4\"><span style=\"color:#333333;\">Mailbox is likely real; verifier just can\u2019t see clearly.<\/span><\/td>\n<\/tr>\n<tr class=\"row-7\">\n\t<td class=\"column-1\"><span style=\"color:#1F2D3D;\"><strong>verifier_timeout<\/strong><\/span><\/td><td class=\"column-2\"><span style=\"color:#333333;\">Unknown<\/span><\/td><td class=\"column-3\"><span style=\"color:#333333;\">Soft-accept + flag<\/span><\/td><td class=\"column-4\"><span style=\"color:#333333;\">Re-verify in next bulk run.<\/span><\/td>\n<\/tr>\n<tr class=\"row-8\">\n\t<td class=\"column-1\"><span style=\"color:#1F2D3D;\"><strong>greylisted<\/strong><\/span><\/td><td class=\"column-2\"><span style=\"color:#333333;\">Unknown<\/span><\/td><td class=\"column-3\"><span style=\"color:#333333;\">Soft-accept + flag<\/span><\/td><td class=\"column-4\"><span style=\"color:#333333;\">Mailbox usually real; first probe failed.<\/span><\/td>\n<\/tr>\n<tr class=\"row-9\">\n\t<td class=\"column-1\"><span style=\"color:#1F2D3D;\"><strong>server_unavailable<\/strong><\/span><\/td><td class=\"column-2\"><span style=\"color:#333333;\">Unknown<\/span><\/td><td class=\"column-3\"><span style=\"color:#333333;\">Soft-accept + flag<\/span><\/td><td class=\"column-4\"><span style=\"color:#333333;\">Recipient infrastructure issue, not your problem.<\/span><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<!-- #tablepress-122 from cache -->\n<p>If you want the technical context behind why these reasons happen at the SMTP layer, our deeper guide on <a href=\"https:\/\/www.emailverify.io\/blog\/smtp-verification\/\" target=\"_blank\" rel=\"noopener\">SMTP verification<\/a> walks through the protocol-level mechanics for catch-all, greylisting, and anti-probe behavior.<\/p>\n<h2><span class=\"ez-toc-section\" id=\"how-should-you-cache-email-verification-results\"><\/span>How Should You Cache Email Verification Results?<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>If the same email is verified twice in close succession, you don&#8217;t need to call the API twice. A short-term cache cuts your verification cost meaningfully and improves perceived performance.<\/p>\n<p>The right cache duration depends on the use case. For a signup flow, a short cache of a few minutes is plenty. For longer-lived caching across multiple flows, a longer cache makes sense, but it should still expire because mailbox state changes over time.<\/p>\n\n<table id=\"tablepress-121\" class=\"tablepress tablepress-id-121\">\n<thead>\n<tr class=\"row-1\">\n\t<th class=\"column-1\"><span style=\"color:#FFFFFF;\"><strong>Use case<\/strong><\/span><\/th><th class=\"column-2\"><span style=\"color:#FFFFFF;\"><strong>Reasonable cache duration<\/strong><\/span><\/th>\n<\/tr>\n<\/thead>\n<tbody class=\"row-striping row-hover\">\n<tr class=\"row-2\">\n\t<td class=\"column-1\"><span style=\"color:#1F2D3D;\"><strong>Single signup form (retry protection)<\/strong><\/span><\/td><td class=\"column-2\"><span style=\"color:#333333;\">5 minutes.<\/span><\/td>\n<\/tr>\n<tr class=\"row-3\">\n\t<td class=\"column-1\"><span style=\"color:#1F2D3D;\"><strong>Multi-step signup (same session)<\/strong><\/span><\/td><td class=\"column-2\"><span style=\"color:#333333;\">15\u201360 minutes.<\/span><\/td>\n<\/tr>\n<tr class=\"row-4\">\n\t<td class=\"column-1\"><span style=\"color:#1F2D3D;\"><strong>Cross-flow caching (login + signup + ...)<\/strong><\/span><\/td><td class=\"column-2\"><span style=\"color:#333333;\">Up to 24 hours.<\/span><\/td>\n<\/tr>\n<tr class=\"row-5\">\n\t<td class=\"column-1\"><span style=\"color:#1F2D3D;\"><strong>Long-term contact record cache<\/strong><\/span><\/td><td class=\"column-2\"><span style=\"color:#333333;\">Don\u2019t cache; re-verify on a bulk schedule instead.<\/span><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<!-- #tablepress-121 from cache -->\n<div class=\"code-terminal-box\">\n<div class=\"code-label\">Cache pattern (Python pseudocode):<\/div>\n<div class=\"code-content\">\n<div>def verify_email_cached(email):<\/div>\n<div>key = f&#8217;verify:{hash_email(email.lower())}&#8217;<\/div>\n<div>cached = redis.get(key)<\/div>\n<div>if cached:<\/div>\n<div>return json.loads(cached)<\/div>\n<div><\/div>\n<div>result = verify_email_uncached(email)<\/div>\n<div>if result[&#8216;status&#8217;] in (&#8216;valid&#8217;, &#8216;invalid&#8217;):<\/div>\n<div>redis.setex(key, 300, json.dumps(result))<\/div>\n<div>return result<\/div>\n<\/div>\n<\/div>\n<h2><span class=\"ez-toc-section\" id=\"how-do-you-implement-rate-limiting-for-email-verification-apis\"><\/span>How Do You Implement Rate Limiting for Email Verification APIs?<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Once your verification endpoint is live and reachable from a public form, it&#8217;s a target. Bots will hit it for various reasons. Without rate limiting on your side, your verifier costs can spike unexpectedly.<\/p>\n<p>The minimum rate-limiting setup includes:<\/p>\n<ul>\n<li>Per-IP rate limit on your \/api\/verify-email endpoint (e.g., 30 requests per minute per IP).<\/li>\n<li>Per-session rate limit (e.g., 10 verifications per session).<\/li>\n<li>CAPTCHA or similar challenge on signup forms experiencing unusual activity.<\/li>\n<li>Monitoring for anomaly patterns: same IP verifying many addresses with the same domain.<\/li>\n<\/ul>\n<div class=\"info-box box-blue\">\n<div class=\"box-label\">Key Insight<\/div>\n<p>Rate limiting is also a security feature, not just a cost feature. Unprotected verification endpoints can be used to probe whether specific email addresses exist. Adding per-IP and per-session limits prevents this enumeration without affecting legitimate signup traffic.<\/p>\n<\/div>\n<h2><span class=\"ez-toc-section\" id=\"common-implementation-mistakes\"><\/span>Common Implementation Mistakes<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Even well-built email verification systems often break down in predictable ways. Below are the most common pitfalls you should actively avoid when implementing an email verification API.<\/p>\n<h3>Calling the API from the Browser with Your Secret Key<\/h3>\n<p>Anyone who looks at your page source has your API key. Always proxy through your own server.<\/p>\n<h3>Hard-Blocking Without a Timeout Fallback<\/h3>\n<p>If your form depends on the verifier responding, every API outage breaks every signup.<\/p>\n<h3>Treating Risky and Unknown as Undeliverable<\/h3>\n<p>Catch-all and anti-probe-provider addresses are common; treating them as hard blocks costs real signups.<\/p>\n<h3>Not Debouncing Typing-Time Verification<\/h3>\n<p>If you wire the API call without a delay, every keystroke fires a new request. Always debounce by 400\u2013800ms.<\/p>\n<h3>Forgetting to Validate Syntax Before the API Call<\/h3>\n<p>If the user typed &#8220;jane&#8221; without an @ symbol, you don&#8217;t need an API call to know it&#8217;s not valid.<\/p>\n<h3>Storing Verification Results Without an Expiration<\/h3>\n<p>Mailbox state changes, and outdated records increase the risk of hitting <a href=\"https:\/\/www.emailverify.io\/blog\/spam-traps\/\" target=\"_blank\" rel=\"noopener\">spam traps<\/a>.<\/p>\n<div class=\"info-box box-red\">\n<div class=\"box-label\">Common Mistake<\/div>\n<p>Logging the full verification response, including the email address, in plain text production logs. Verification responses contain PII; treat them with the same care as any other user data. Use structured logging with PII fields tagged for redaction, and don\u2019t print full email addresses to the console in production.<\/p>\n<\/div>\n<h2><span class=\"ez-toc-section\" id=\"how-do-you-test-an-email-verification-api-integration\"><\/span>How Do You Test an Email Verification API Integration?<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>A working integration handles all four primary statuses correctly, plus the timeout case. Most vendors provide test addresses you can use to deterministically trigger each status. EmailVerify.io has a set of test addresses documented in the API reference; if your vendor doesn&#8217;t, you can construct equivalents.<\/p>\n<p>The minimum test suite covers:<\/p>\n\n<table id=\"tablepress-120\" class=\"tablepress tablepress-id-120\">\n<thead>\n<tr class=\"row-1\">\n\t<th class=\"column-1\"><span style=\"color:#FFFFFF;\"><strong>Test case<\/strong><\/span><\/th><th class=\"column-2\"><span style=\"color:#FFFFFF;\"><strong>What to send<\/strong><\/span><\/th><th class=\"column-3\"><span style=\"color:#FFFFFF;\"><strong>Expected response<\/strong><\/span><\/th>\n<\/tr>\n<\/thead>\n<tbody class=\"row-striping row-hover\">\n<tr class=\"row-2\">\n\t<td class=\"column-1\"><span style=\"color:#1F2D3D;\"><strong>Valid<\/strong><\/span><\/td><td class=\"column-2\"><span style=\"color:#333333;\">A real address you control.<\/span><\/td><td class=\"column-3\"><span style=\"color:#333333;\">status: Valid<\/span><\/td>\n<\/tr>\n<tr class=\"row-3\">\n\t<td class=\"column-1\"><span style=\"color:#1F2D3D;\"><strong>Invalid, bad syntax<\/strong><\/span><\/td><td class=\"column-2\"><span style=\"color:#333333;\">An address with a missing @ or invalid characters.<\/span><\/td><td class=\"column-3\"><span style=\"color:#333333;\">status: Invalid, reason: invalid_syntax<\/span><\/td>\n<\/tr>\n<tr class=\"row-4\">\n\t<td class=\"column-1\"><span style=\"color:#1F2D3D;\"><strong>Invalid, dead mailbox<\/strong><\/span><\/td><td class=\"column-2\"><span style=\"color:#333333;\">An invented local part at a real domain.<\/span><\/td><td class=\"column-3\"><span style=\"color:#333333;\">status: invalid, reason: mailbox_not_found<\/span><\/td>\n<\/tr>\n<tr class=\"row-5\">\n\t<td class=\"column-1\"><span style=\"color:#1F2D3D;\"><strong>Invalid, no MX<\/strong><\/span><\/td><td class=\"column-2\"><span style=\"color:#333333;\">An address at a domain with no MX records.<\/span><\/td><td class=\"column-3\"><span style=\"color:#333333;\">status: invalid, reason: no_mx<\/span><\/td>\n<\/tr>\n<tr class=\"row-6\">\n\t<td class=\"column-1\"><span style=\"color:#1F2D3D;\"><strong>Risky, catch-all<\/strong><\/span><\/td><td class=\"column-2\"><span style=\"color:#333333;\">An address at a known catch-all test domain.<\/span><\/td><td class=\"column-3\"><span style=\"color:#333333;\">status: risky, reason: catch_all<\/span><\/td>\n<\/tr>\n<tr class=\"row-7\">\n\t<td class=\"column-1\"><span style=\"color:#1F2D3D;\"><strong>Risky, disposable<\/strong><\/span><\/td><td class=\"column-2\"><span style=\"color:#333333;\">An address at a known disposable provider.<\/span><\/td><td class=\"column-3\"><span style=\"color:#333333;\">status: risky, reason: disposable<\/span><\/td>\n<\/tr>\n<tr class=\"row-8\">\n\t<td class=\"column-1\"><span style=\"color:#1F2D3D;\"><strong>Risky, role-based<\/strong><\/span><\/td><td class=\"column-2\"><span style=\"color:#333333;\">info@yourcompany.com or similar.<\/span><\/td><td class=\"column-3\"><span style=\"color:#333333;\">status: risky, reason: role_based<\/span><\/td>\n<\/tr>\n<tr class=\"row-9\">\n\t<td class=\"column-1\"><span style=\"color:#1F2D3D;\"><strong>Verifier timeout<\/strong><\/span><\/td><td class=\"column-2\"><span style=\"color:#333333;\">Mock a slow API response in your test setup.<\/span><\/td><td class=\"column-3\"><span style=\"color:#333333;\">status: unknown, reason: verifier_timeout<\/span><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<!-- #tablepress-120 from cache -->\n<div class=\"info-box box-yellow\">\n<div class=\"box-label\">Checklist<\/div>\n<p>Pre-launch integration checklist:<\/p>\n<ul>\n<li>API key stored as a server-side environment variable.<\/li>\n<li>Server-side proxy endpoint set up at \/api\/verify-email.<\/li>\n<li>1\u20132 second timeout with soft-accept fallback wired in.<\/li>\n<li>Four-tier UX matrix implemented, with reason-code-specific messages.<\/li>\n<li>Debouncing applied if verifying during typing.<\/li>\n<li>Per-IP and per-session rate limiting on the proxy endpoint.<\/li>\n<li>Cache layer with sensible TTL for retry protection.<\/li>\n<li>All test cases produce expected UX behavior.<\/li>\n<li>PII handled correctly in logs (no plaintext email addresses).<\/li>\n<\/ul>\n<\/div>\n<h2><span class=\"ez-toc-section\" id=\"how-does-emailverifyio-support-this-pattern\"><\/span>How Does EmailVerify.io Support This Pattern?<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p><a href=\"https:\/\/emailverify.io\/api\/\" target=\"_blank\" rel=\"noopener\">EmailVerify.io&#8217;s API<\/a> is built around this exact integration pattern. Sub-second responses for most addresses, a structured multi-status output (Valid, Invalid, Catch-All, Disposable, Do Not Mail, Role-Based, Unknown, and Skipped), and clear documentation of which statuses can occur and what they mean.<\/p>\n<p>Full endpoint references, authentication details, sample requests in multiple languages, and the complete status list are on the <a href=\"https:\/\/emailverify.io\/api\/\" target=\"_blank\" rel=\"noopener\">EmailVerify.io API page<\/a> and the deeper <a href=\"https:\/\/www.emailverify.io\/docs\/api-documentation\" target=\"_blank\" rel=\"noopener\">API documentation<\/a>. The patterns in this article work directly against that API; the snippets above will run with the right environment variable set and an active key.<\/p>\n<p><img fetchpriority=\"high\" decoding=\"async\" class=\"alignnone size-large wp-image-2504\" src=\"https:\/\/www.emailverify.io\/blog\/wp-content\/uploads\/2026\/05\/Email-Verification-API-1024x624.webp\" alt=\"Three-column architecture diagram showing browser, application server, and EmailVerify.io with timeout fallback, rate limiter, and cache layer attached to the server\" width=\"1024\" height=\"624\" srcset=\"https:\/\/www.emailverify.io\/blog\/wp-content\/uploads\/2026\/05\/Email-Verification-API-1024x624.webp 1024w, https:\/\/www.emailverify.io\/blog\/wp-content\/uploads\/2026\/05\/Email-Verification-API-300x183.webp 300w, https:\/\/www.emailverify.io\/blog\/wp-content\/uploads\/2026\/05\/Email-Verification-API-150x91.webp 150w, https:\/\/www.emailverify.io\/blog\/wp-content\/uploads\/2026\/05\/Email-Verification-API-768x468.webp 768w, https:\/\/www.emailverify.io\/blog\/wp-content\/uploads\/2026\/05\/Email-Verification-API-1536x936.webp 1536w, https:\/\/www.emailverify.io\/blog\/wp-content\/uploads\/2026\/05\/Email-Verification-API-450x274.webp 450w, https:\/\/www.emailverify.io\/blog\/wp-content\/uploads\/2026\/05\/Email-Verification-API-780x475.webp 780w, https:\/\/www.emailverify.io\/blog\/wp-content\/uploads\/2026\/05\/Email-Verification-API-1600x975.webp 1600w, https:\/\/www.emailverify.io\/blog\/wp-content\/uploads\/2026\/05\/Email-Verification-API.webp 1672w\" sizes=\"(max-width: 1024px) 100vw, 1024px\" \/><\/p>\n<div class=\"info-box box-blue\">\n<div class=\"box-label\">Expert Tip<\/div>\n<p>If you\u2019re evaluating EmailVerify.io against another vendor, the easiest test is to run the same eight-case test suite from Section 16 against both APIs. The schema, the reason codes, and the latency should match what you\u2019d expect from a production integration.<\/p>\n<\/div>\n<h2><span class=\"ez-toc-section\" id=\"frequently-asked-questions\"><\/span>Frequently Asked Questions<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<style>#sp-ea-2490 .spcollapsing { height: 0; overflow: hidden; transition-property: height;transition-duration: 300ms;}#sp-ea-2490.sp-easy-accordion>.sp-ea-single {margin-bottom: 10px; border: 1px solid #e2e2e2; }#sp-ea-2490.sp-easy-accordion>.sp-ea-single>.ea-header a {color: #444;}#sp-ea-2490.sp-easy-accordion>.sp-ea-single>.sp-collapse>.ea-body {background: #fff; color: #444;}#sp-ea-2490.sp-easy-accordion>.sp-ea-single {background: #eee;}#sp-ea-2490.sp-easy-accordion>.sp-ea-single>.ea-header a .ea-expand-icon { float: left; color: #444;font-size: 16px;}<\/style><div id=\"sp_easy_accordion-1777987739\"><div id=\"sp-ea-2490\" class=\"sp-ea-one sp-easy-accordion\" data-ea-active=\"ea-click\" data-ea-mode=\"vertical\" data-preloader=\"\" data-scroll-active-item=\"\" data-offset-to-scroll=\"0\"><div class=\"ea-card ea-expand sp-ea-single\"><h3 class=\"ea-header\"><a class=\"collapsed\" id=\"ea-header-24900\" role=\"button\" data-sptoggle=\"spcollapse\" data-sptarget=\"#collapse24900\" aria-controls=\"collapse24900\" href=\"#\" aria-expanded=\"true\" tabindex=\"0\"><i aria-hidden=\"true\" role=\"presentation\" class=\"ea-expand-icon eap-icon-ea-expand-minus\"><\/i> What Is an Email Verification API?<\/a><\/h3><div class=\"sp-collapse spcollapse collapsed show\" id=\"collapse24900\" data-parent=\"#sp-ea-2490\" role=\"region\" aria-labelledby=\"ea-header-24900\"> <div class=\"ea-body\"><p>An email verification API checks if an email address is real and able to receive mail. It validates syntax, domain, MX records, and mailbox status, then returns a structured result like Valid, Risky, Unknown, or Invalid with reason codes.<\/p><\/div><\/div><\/div><div class=\"ea-card sp-ea-single\"><h3 class=\"ea-header\"><a class=\"collapsed\" id=\"ea-header-24901\" role=\"button\" data-sptoggle=\"spcollapse\" data-sptarget=\"#collapse24901\" aria-controls=\"collapse24901\" href=\"#\" aria-expanded=\"false\" tabindex=\"0\"><i aria-hidden=\"true\" role=\"presentation\" class=\"ea-expand-icon eap-icon-ea-expand-plus\"><\/i> Where Should I Call the Email Verification API in a Signup Flow?<\/a><\/h3><div class=\"sp-collapse spcollapse \" id=\"collapse24901\" data-parent=\"#sp-ea-2490\" role=\"region\" aria-labelledby=\"ea-header-24901\"> <div class=\"ea-body\"><p>From your application server, not from the browser. The API key is a secret; if you put it in client-side JavaScript, anyone can extract and abuse it. The right pattern is to expose your own \/api\/verify-email endpoint that proxies the call to the verification API server-side. As for timing, fire the call when the email field loses focus (on blur) so the result is back by the time the user clicks submit.<\/p><\/div><\/div><\/div><div class=\"ea-card sp-ea-single\"><h3 class=\"ea-header\"><a class=\"collapsed\" id=\"ea-header-24902\" role=\"button\" data-sptoggle=\"spcollapse\" data-sptarget=\"#collapse24902\" aria-controls=\"collapse24902\" href=\"#\" aria-expanded=\"false\" tabindex=\"0\"><i aria-hidden=\"true\" role=\"presentation\" class=\"ea-expand-icon eap-icon-ea-expand-plus\"><\/i> How Fast Is a Real-Time Email Verification API?<\/a><\/h3><div class=\"sp-collapse spcollapse \" id=\"collapse24902\" data-parent=\"#sp-ea-2490\" role=\"region\" aria-labelledby=\"ea-header-24902\"> <div class=\"ea-body\"><p>In well-designed APIs, sub-second per address. The bottleneck is the SMTP probe to the recipient mail server, which the API handles with connection pooling, IP rotation, and retry logic. From your application's perspective, a successful call returns in well under a second. Set a 1\u20132 second timeout to handle the rare cases where the API is slow.<\/p><\/div><\/div><\/div><div class=\"ea-card sp-ea-single\"><h3 class=\"ea-header\"><a class=\"collapsed\" id=\"ea-header-24903\" role=\"button\" data-sptoggle=\"spcollapse\" data-sptarget=\"#collapse24903\" aria-controls=\"collapse24903\" href=\"#\" aria-expanded=\"false\" tabindex=\"0\"><i aria-hidden=\"true\" role=\"presentation\" class=\"ea-expand-icon eap-icon-ea-expand-plus\"><\/i> What Should I Do When the API Times Out? <\/a><\/h3><div class=\"sp-collapse spcollapse \" id=\"collapse24903\" data-parent=\"#sp-ea-2490\" role=\"region\" aria-labelledby=\"ea-header-24903\"> <div class=\"ea-body\"><p>Soft-accept the address with a flag for later bulk re-verification. Treating timeouts as a hard block would prevent legitimate users from signing up during any verifier outage. The 1\u20132 second timeout combined with a soft-accept fallback is the production pattern; verification should never become the reason a real user can't sign up.<\/p><\/div><\/div><\/div><div class=\"ea-card sp-ea-single\"><h3 class=\"ea-header\"><a class=\"collapsed\" id=\"ea-header-24904\" role=\"button\" data-sptoggle=\"spcollapse\" data-sptarget=\"#collapse24904\" aria-controls=\"collapse24904\" href=\"#\" aria-expanded=\"false\" tabindex=\"0\"><i aria-hidden=\"true\" role=\"presentation\" class=\"ea-expand-icon eap-icon-ea-expand-plus\"><\/i> Can I Cache Email Verification Results? <\/a><\/h3><div class=\"sp-collapse spcollapse \" id=\"collapse24904\" data-parent=\"#sp-ea-2490\" role=\"region\" aria-labelledby=\"ea-header-24904\"> <div class=\"ea-body\"><p>Yes. Use short-lived caching:<\/p><ul><li>Signup retry: 5 minutes<\/li><li>Multi-step forms: 15\u201360 minutes<\/li><li>Cross-flow use: up to 24 hours<\/li><li>Long-term storage: avoid caching<\/li><\/ul><p>Cache only stable results like Valid or Invalid.<\/p><\/div><\/div><\/div><div class=\"ea-card sp-ea-single\"><h3 class=\"ea-header\"><a class=\"collapsed\" id=\"ea-header-24905\" role=\"button\" data-sptoggle=\"spcollapse\" data-sptarget=\"#collapse24905\" aria-controls=\"collapse24905\" href=\"#\" aria-expanded=\"false\" tabindex=\"0\"><i aria-hidden=\"true\" role=\"presentation\" class=\"ea-expand-icon eap-icon-ea-expand-plus\"><\/i> Do I Still Need Server-Side Validation If I Use an API? <\/a><\/h3><div class=\"sp-collapse spcollapse \" id=\"collapse24905\" data-parent=\"#sp-ea-2490\" role=\"region\" aria-labelledby=\"ea-header-24905\"> <div class=\"ea-body\"><p>Yes. Always validate syntax before calling the API, both for cost reasons (don't burn credits on obvious garbage) and for safety (the API is one component of your input handling, not all of it). A simple regex or library check filters out the most obviously malformed inputs; the API takes care of everything else.<\/p><\/div><\/div><\/div><div class=\"ea-card sp-ea-single\"><h3 class=\"ea-header\"><a class=\"collapsed\" id=\"ea-header-24906\" role=\"button\" data-sptoggle=\"spcollapse\" data-sptarget=\"#collapse24906\" aria-controls=\"collapse24906\" href=\"#\" aria-expanded=\"false\" tabindex=\"0\"><i aria-hidden=\"true\" role=\"presentation\" class=\"ea-expand-icon eap-icon-ea-expand-plus\"><\/i> Should I Block Disposable Email Addresses? <\/a><\/h3><div class=\"sp-collapse spcollapse \" id=\"collapse24906\" data-parent=\"#sp-ea-2490\" role=\"region\" aria-labelledby=\"ea-header-24906\"> <div class=\"ea-body\"><p>Usually yes, for signup forms tied to free trials, free accounts, or anything where one user shouldn't have unlimited accounts. Block with a clear message asking for a permanent address. For paid signups or business contexts, the case for blocking is weaker; some legitimate users (privacy-conscious technical users, etc.) use disposable addresses on purpose.<\/p><\/div><\/div><\/div><div class=\"ea-card sp-ea-single\"><h3 class=\"ea-header\"><a class=\"collapsed\" id=\"ea-header-24907\" role=\"button\" data-sptoggle=\"spcollapse\" data-sptarget=\"#collapse24907\" aria-controls=\"collapse24907\" href=\"#\" aria-expanded=\"false\" tabindex=\"0\"><i aria-hidden=\"true\" role=\"presentation\" class=\"ea-expand-icon eap-icon-ea-expand-plus\"><\/i> How Does Email Verification Handle Yahoo and AOL Emails? <\/a><\/h3><div class=\"sp-collapse spcollapse \" id=\"collapse24907\" data-parent=\"#sp-ea-2490\" role=\"region\" aria-labelledby=\"ea-header-24907\"> <div class=\"ea-body\"><p>Honestly, with caveats. Yahoo and AOL deliberately obscure their RCPT TO responses, so a clean, SMTP-level valid answer isn't available for those providers. A good verifier returns \"Risky\" with a reason code naming the provider so your UX matrix can branch on it. Most teams accept these addresses on signup; engagement signals over time tell you whether the mailbox is real.<\/p><\/div><\/div><\/div><\/div><\/div>\n<h2><span class=\"ez-toc-section\" id=\"final-thoughts\"><\/span>Final Thoughts<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>The email verification API is a small piece of infrastructure that does an outsized amount of work for a signup flow. Wired in correctly, it catches typos, blocks bots, prevents disposable signups, and keeps your contact database clean from the moment of entry. Wired in badly, it slows down forms, blocks real users, leaks API keys, and runs up unexpected bills.<\/p>\n<p>The patterns in this article are the difference. Server-side proxy. Sub-second timeout with soft-accept fallback. Four-tier UX matrix that handles each status with the message that fits. Debouncing on typing-time verification. Rate limiting on the public endpoint. Caching with a sensible TTL. PII safety in logs. Each of these is a small thing on its own; together they&#8217;re the production pattern.<\/p>\n<p>The code in this article works. Drop the snippets into your application server, set an environment variable for the API key, and wire the endpoint into your form, and you have a working integration. The harder work is the operational logic around it, and that&#8217;s exactly what most of this article has been about. Pick the pieces that fit your stack, ignore the rest, and ship something that protects your data without breaking your funnel.<\/p>\n<p>Cleaner signup data. Fewer typos. No bot accounts. That&#8217;s what a <a href=\"https:\/\/www.emailverify.io\/services\/email-verify\/\" target=\"_blank\" rel=\"noopener\">trusted email verification service<\/a> delivers when it&#8217;s integrated well.<\/p>\n<div class=\"blogDetailCtaWrapper\">\n<div class=\"blogDetailCtaContainer\">\n<p class=\"ctaMainHeading\">Get an API key and ship the integration<\/p>\n<p>Grab an API key from the <a href=\"http:\/\/EmailVerify.io\" target=\"_blank\" rel=\"noopener\">EmailVerify.io<\/a> API page, drop the <a href=\"https:\/\/pypi.org\/project\/emailverifysdk\/\" rel=\"nofollow\" target=\"_blank\">Python<\/a>, <a href=\"https:\/\/www.npmjs.com\/package\/@emailverifyio\/emailverify-sdk\" rel=\"nofollow\" target=\"_blank\">Node<\/a>, or <a href=\"https:\/\/packagist.org\/packages\/emailverifyio\/emailverify\" rel=\"nofollow\" target=\"_blank\">PHP snippet<\/a> into your server, and your signup form is verifying addresses in production within an hour.<\/p>\n<p><a class=\"ctaButton\" href=\"https:\/\/emailverify.io\/api\/\" target=\"_blank\" rel=\"noopener\">Get API Key<\/a><\/p>\n<\/div>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>If you&#8217;re a developer responsible for a signup form, this guide is for you. If you\u2019re building a signup flow, email quality is one of the first things that can break it. Users mistype addresses, bots submit fake emails, and disposable inboxes slip through. Left unchecked, this leads to poor deliverability, wasted campaigns, and unreliable [&hellip;]<\/p>\n","protected":false},"author":6,"featured_media":2505,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[31],"tags":[],"class_list":["post-2489","post","type-post","status-publish","format-standard","has-post-thumbnail","category-email-verification"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.7 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>How to Use an Email Verification API for Signup Flows (Complete Guide)<\/title>\n<meta name=\"description\" content=\"A complete guide to email verification API integration for signup forms. Validate emails in real time, handle risky statuses, and boost deliverability with Node, Python, PHP examples.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.emailverify.io\/blog\/email-verification-api-guide\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"How to Use an Email Verification API for Signup Flows (Complete Guide)\" \/>\n<meta property=\"og:description\" content=\"A complete guide to email verification API integration for signup forms. Validate emails in real time, handle risky statuses, and boost deliverability with Node, Python, PHP examples.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.emailverify.io\/blog\/email-verification-api-guide\/\" \/>\n<meta property=\"og:site_name\" content=\"EmailVerify\" \/>\n<meta property=\"article:published_time\" content=\"2026-05-05T14:07:57+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-05-12T06:26:03+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.emailverify.io\/blog\/wp-content\/uploads\/2026\/05\/Email-Verification-API-1.webp\" \/>\n\t<meta property=\"og:image:width\" content=\"1672\" \/>\n\t<meta property=\"og:image:height\" content=\"986\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/webp\" \/>\n<meta name=\"author\" content=\"Fiza Shahid\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Fiza Shahid\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"16 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.emailverify.io\\\/blog\\\/email-verification-api-guide\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.emailverify.io\\\/blog\\\/email-verification-api-guide\\\/\"},\"author\":{\"name\":\"Fiza Shahid\",\"@id\":\"https:\\\/\\\/www.emailverify.io\\\/blog\\\/#\\\/schema\\\/person\\\/27f378aa512f5db093f5107baa4b006d\"},\"headline\":\"Email Verification API: How to Verify Emails at Signup\",\"datePublished\":\"2026-05-05T14:07:57+00:00\",\"dateModified\":\"2026-05-12T06:26:03+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.emailverify.io\\\/blog\\\/email-verification-api-guide\\\/\"},\"wordCount\":3591,\"commentCount\":0,\"image\":{\"@id\":\"https:\\\/\\\/www.emailverify.io\\\/blog\\\/email-verification-api-guide\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.emailverify.io\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/05\\\/Email-Verification-API-1.webp\",\"articleSection\":[\"Email Verification\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.emailverify.io\\\/blog\\\/email-verification-api-guide\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.emailverify.io\\\/blog\\\/email-verification-api-guide\\\/\",\"url\":\"https:\\\/\\\/www.emailverify.io\\\/blog\\\/email-verification-api-guide\\\/\",\"name\":\"How to Use an Email Verification API for Signup Flows (Complete Guide)\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.emailverify.io\\\/blog\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.emailverify.io\\\/blog\\\/email-verification-api-guide\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.emailverify.io\\\/blog\\\/email-verification-api-guide\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.emailverify.io\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/05\\\/Email-Verification-API-1.webp\",\"datePublished\":\"2026-05-05T14:07:57+00:00\",\"dateModified\":\"2026-05-12T06:26:03+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/www.emailverify.io\\\/blog\\\/#\\\/schema\\\/person\\\/27f378aa512f5db093f5107baa4b006d\"},\"description\":\"A complete guide to email verification API integration for signup forms. Validate emails in real time, handle risky statuses, and boost deliverability with Node, Python, PHP examples.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.emailverify.io\\\/blog\\\/email-verification-api-guide\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.emailverify.io\\\/blog\\\/email-verification-api-guide\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.emailverify.io\\\/blog\\\/email-verification-api-guide\\\/#primaryimage\",\"url\":\"https:\\\/\\\/www.emailverify.io\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/05\\\/Email-Verification-API-1.webp\",\"contentUrl\":\"https:\\\/\\\/www.emailverify.io\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/05\\\/Email-Verification-API-1.webp\",\"width\":1672,\"height\":986},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.emailverify.io\\\/blog\\\/email-verification-api-guide\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.emailverify.io\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Email Verification API: How to Verify Emails at Signup\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.emailverify.io\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.emailverify.io\\\/blog\\\/\",\"name\":\"EmailVerify\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.emailverify.io\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.emailverify.io\\\/blog\\\/#\\\/schema\\\/person\\\/27f378aa512f5db093f5107baa4b006d\",\"name\":\"Fiza Shahid\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/bf34fb50702ce6e30c3d7dc9b9a81f48c39b54c9aaf69ef425e29f25ef167350?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/bf34fb50702ce6e30c3d7dc9b9a81f48c39b54c9aaf69ef425e29f25ef167350?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/bf34fb50702ce6e30c3d7dc9b9a81f48c39b54c9aaf69ef425e29f25ef167350?s=96&d=mm&r=g\",\"caption\":\"Fiza Shahid\"},\"description\":\"Fiza Shahid is an SEO Content Writer with 1+ years of experience crafting blogs and guides for B2B, SaaS, and digital marketing industries. She creates SEO-focused, reader-friendly content that enhances online visibility, builds brand trust, and drives meaningful engagement. Known for simplifying technical topics into actionable insights, Fiza helps businesses strengthen communication strategies and achieve measurable results.\",\"url\":\"https:\\\/\\\/www.emailverify.io\\\/blog\\\/author\\\/fiza-shahid\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"How to Use an Email Verification API for Signup Flows (Complete Guide)","description":"A complete guide to email verification API integration for signup forms. Validate emails in real time, handle risky statuses, and boost deliverability with Node, Python, PHP examples.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.emailverify.io\/blog\/email-verification-api-guide\/","og_locale":"en_US","og_type":"article","og_title":"How to Use an Email Verification API for Signup Flows (Complete Guide)","og_description":"A complete guide to email verification API integration for signup forms. Validate emails in real time, handle risky statuses, and boost deliverability with Node, Python, PHP examples.","og_url":"https:\/\/www.emailverify.io\/blog\/email-verification-api-guide\/","og_site_name":"EmailVerify","article_published_time":"2026-05-05T14:07:57+00:00","article_modified_time":"2026-05-12T06:26:03+00:00","og_image":[{"width":1672,"height":986,"url":"https:\/\/www.emailverify.io\/blog\/wp-content\/uploads\/2026\/05\/Email-Verification-API-1.webp","type":"image\/webp"}],"author":"Fiza Shahid","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Fiza Shahid","Est. reading time":"16 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.emailverify.io\/blog\/email-verification-api-guide\/#article","isPartOf":{"@id":"https:\/\/www.emailverify.io\/blog\/email-verification-api-guide\/"},"author":{"name":"Fiza Shahid","@id":"https:\/\/www.emailverify.io\/blog\/#\/schema\/person\/27f378aa512f5db093f5107baa4b006d"},"headline":"Email Verification API: How to Verify Emails at Signup","datePublished":"2026-05-05T14:07:57+00:00","dateModified":"2026-05-12T06:26:03+00:00","mainEntityOfPage":{"@id":"https:\/\/www.emailverify.io\/blog\/email-verification-api-guide\/"},"wordCount":3591,"commentCount":0,"image":{"@id":"https:\/\/www.emailverify.io\/blog\/email-verification-api-guide\/#primaryimage"},"thumbnailUrl":"https:\/\/www.emailverify.io\/blog\/wp-content\/uploads\/2026\/05\/Email-Verification-API-1.webp","articleSection":["Email Verification"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.emailverify.io\/blog\/email-verification-api-guide\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.emailverify.io\/blog\/email-verification-api-guide\/","url":"https:\/\/www.emailverify.io\/blog\/email-verification-api-guide\/","name":"How to Use an Email Verification API for Signup Flows (Complete Guide)","isPartOf":{"@id":"https:\/\/www.emailverify.io\/blog\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.emailverify.io\/blog\/email-verification-api-guide\/#primaryimage"},"image":{"@id":"https:\/\/www.emailverify.io\/blog\/email-verification-api-guide\/#primaryimage"},"thumbnailUrl":"https:\/\/www.emailverify.io\/blog\/wp-content\/uploads\/2026\/05\/Email-Verification-API-1.webp","datePublished":"2026-05-05T14:07:57+00:00","dateModified":"2026-05-12T06:26:03+00:00","author":{"@id":"https:\/\/www.emailverify.io\/blog\/#\/schema\/person\/27f378aa512f5db093f5107baa4b006d"},"description":"A complete guide to email verification API integration for signup forms. Validate emails in real time, handle risky statuses, and boost deliverability with Node, Python, PHP examples.","breadcrumb":{"@id":"https:\/\/www.emailverify.io\/blog\/email-verification-api-guide\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.emailverify.io\/blog\/email-verification-api-guide\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.emailverify.io\/blog\/email-verification-api-guide\/#primaryimage","url":"https:\/\/www.emailverify.io\/blog\/wp-content\/uploads\/2026\/05\/Email-Verification-API-1.webp","contentUrl":"https:\/\/www.emailverify.io\/blog\/wp-content\/uploads\/2026\/05\/Email-Verification-API-1.webp","width":1672,"height":986},{"@type":"BreadcrumbList","@id":"https:\/\/www.emailverify.io\/blog\/email-verification-api-guide\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.emailverify.io\/blog\/"},{"@type":"ListItem","position":2,"name":"Email Verification API: How to Verify Emails at Signup"}]},{"@type":"WebSite","@id":"https:\/\/www.emailverify.io\/blog\/#website","url":"https:\/\/www.emailverify.io\/blog\/","name":"EmailVerify","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.emailverify.io\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.emailverify.io\/blog\/#\/schema\/person\/27f378aa512f5db093f5107baa4b006d","name":"Fiza Shahid","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/bf34fb50702ce6e30c3d7dc9b9a81f48c39b54c9aaf69ef425e29f25ef167350?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/bf34fb50702ce6e30c3d7dc9b9a81f48c39b54c9aaf69ef425e29f25ef167350?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/bf34fb50702ce6e30c3d7dc9b9a81f48c39b54c9aaf69ef425e29f25ef167350?s=96&d=mm&r=g","caption":"Fiza Shahid"},"description":"Fiza Shahid is an SEO Content Writer with 1+ years of experience crafting blogs and guides for B2B, SaaS, and digital marketing industries. She creates SEO-focused, reader-friendly content that enhances online visibility, builds brand trust, and drives meaningful engagement. Known for simplifying technical topics into actionable insights, Fiza helps businesses strengthen communication strategies and achieve measurable results.","url":"https:\/\/www.emailverify.io\/blog\/author\/fiza-shahid\/"}]}},"_links":{"self":[{"href":"https:\/\/www.emailverify.io\/blog\/wp-json\/wp\/v2\/posts\/2489","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.emailverify.io\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.emailverify.io\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.emailverify.io\/blog\/wp-json\/wp\/v2\/users\/6"}],"replies":[{"embeddable":true,"href":"https:\/\/www.emailverify.io\/blog\/wp-json\/wp\/v2\/comments?post=2489"}],"version-history":[{"count":6,"href":"https:\/\/www.emailverify.io\/blog\/wp-json\/wp\/v2\/posts\/2489\/revisions"}],"predecessor-version":[{"id":2812,"href":"https:\/\/www.emailverify.io\/blog\/wp-json\/wp\/v2\/posts\/2489\/revisions\/2812"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.emailverify.io\/blog\/wp-json\/wp\/v2\/media\/2505"}],"wp:attachment":[{"href":"https:\/\/www.emailverify.io\/blog\/wp-json\/wp\/v2\/media?parent=2489"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.emailverify.io\/blog\/wp-json\/wp\/v2\/categories?post=2489"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.emailverify.io\/blog\/wp-json\/wp\/v2\/tags?post=2489"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}