FastAPI email verification
Verify emails in FastAPI with Verifly
Add a live, async email verification step to any FastAPI app using httpx. Verifly is an API-first, pay-as-you-go service — await a clean JSON verdict inside your endpoint, reject disposable or dead mailboxes, and create the user only when the address is real.
import httpx
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel, EmailStr
app = FastAPI()
KEY = "vf_YOUR_KEY" # load from env, never hard-code in real apps
class NewUser(BaseModel):
email: EmailStr
@app.post("/users", status_code=201)
async def create_user(user: NewUser):
async with httpx.AsyncClient(timeout=8) as client:
r = await client.get(
"https://verifly.email/api/v1/verify",
params={"email": user.email},
headers={"Authorization": f"Bearer {KEY}"},
)
data = r.json()
if data["result"] == "undeliverable" or data.get("disposable"):
raise HTTPException(400, "Please use a valid, permanent email")
# await save_user(user.email)
return {"ok": True}Real-time SMTP mailbox checks
Single, batch, and async bulk verification
Disposable, role account, and catch-all detection
Pay-as-you-go credits with no subscription lock-in
Search fit
Built for FastAPI email verification
Use Verifly when you need a simple API, predictable pricing, and clean JSON results before emails hit your product, CRM, or campaign tool.
Async email verification in FastAPI
FastAPI is async by design, and email verification is an I/O-bound network call — a perfect match. Pydantic's EmailStr already validates that an address is well-formed, but that is only syntax: user@dead-domain.com passes EmailStr and still bounces. The mailbox's real status lives behind an SMTP handshake, and Verifly performs that handshake for you over one HTTPS request that you can await without blocking the event loop.
Because Verifly is a plain REST API, httpx is the idiomatic client — its AsyncClient mirrors requests but returns awaitables. You await a GET to /api/v1/verify with a Bearer key and read a JSON verdict with a result field of deliverable, undeliverable, or risky plus boolean flags for disposable, role, catch_all, and smtp. Put the check just before you persist the user so you never create an account on a dead or throwaway address.
For performance, do not open a fresh AsyncClient per request in production — create one on startup and reuse it via a dependency or app state, which keeps the connection pool warm. Pricing is pay-as-you-go from $2 per 1,000 checks down to $0.60 per 1,000 at volume. Self-register for 100 free credits with no card at the autonomous register endpoint.
Reuse one AsyncClient with a dependency
Creating an httpx.AsyncClient per request adds handshake overhead and wastes connections. Instead, build a single client during the FastAPI lifespan and inject it with Depends. Wrap the verification in a try/except so a transient httpx error fails open — you would rather admit a rare unverified address than 500 a legitimate signup on a network blip.
import httpx
from contextlib import asynccontextmanager
from fastapi import Depends, FastAPI
@asynccontextmanager
async def lifespan(app: FastAPI):
app.state.http = httpx.AsyncClient(timeout=8)
yield
await app.state.http.aclose()
app = FastAPI(lifespan=lifespan)
async def get_client(request) -> httpx.AsyncClient:
return request.app.state.http
async def email_ok(email: str, client: httpx.AsyncClient) -> bool:
try:
r = await client.get(
"https://verifly.email/api/v1/verify",
params={"email": email},
headers={"Authorization": "Bearer vf_YOUR_KEY"},
)
data = r.json()
except httpx.HTTPError:
return True # fail open: never block signup on a network error
return data["result"] != "undeliverable" and not data.get("disposable")Batch-verify a list in an async route
For cleaning a list rather than a single signup, do not gather many single calls — POST them together to /api/v1/verify/batch. It accepts a JSON body with an emails array and returns a results array in the same order, so a single awaited request handles the whole list. Reuse the shared AsyncClient and filter the results down to deliverable addresses.
from fastapi import Depends, FastAPI
import httpx
@app.post("/admin/clean")
async def clean(emails: list[str], client: httpx.AsyncClient = Depends(get_client)):
r = await client.post(
"https://verifly.email/api/v1/verify/batch",
json={"emails": emails},
headers={"Authorization": "Bearer vf_YOUR_KEY"},
)
results = r.json()["results"]
kept = [x["email"] for x in results
if x["result"] == "deliverable" and not x.get("disposable")]
return {"kept": kept, "total": len(results)}FAQ
Frequently asked questions
Should I use httpx or requests in FastAPI?
Use httpx. FastAPI is async, and httpx.AsyncClient lets you await the verification call without blocking the event loop. requests is synchronous and would stall the worker; httpx keeps the endpoint fully non-blocking against Verifly's REST API.
Where should the verification call go in a signup flow?
Just before you persist the user. Await the GET to /api/v1/verify, check the result and disposable fields, and raise an HTTPException(400) if the address is bad. Only call your save/create logic once the address passes.
Do I create a new AsyncClient per request?
No. Build one httpx.AsyncClient in the lifespan handler, store it on app.state, and inject it with Depends. Reusing the client keeps the connection pool warm and cuts per-request latency significantly.
How do I keep a network error from breaking signups?
Wrap the httpx call in try/except httpx.HTTPError and fail open — return True (acceptable) on error so a transient blip lets the registration through. Only reject when Verifly positively reports the address undeliverable or disposable.
How do I verify many addresses at once?
Await a single POST to /api/v1/verify/batch with a JSON emails array and read the results array. That is far faster than awaiting the single endpoint per address, even with asyncio.gather.
What does FastAPI email verification cost?
Pricing is pay-as-you-go from $2 per 1,000 checks down to $0.60 per 1,000 at volume, with 100 free credits when you self-register. There is no subscription, so a low-traffic API costs only the credits it spends. Verifly also exposes an MCP server at verifly.email/mcp for AI agents.