Back to blogtutorial

Email Verification API for Developers: Send & Verify OTPs

Email Verification API for Developers: Send & Verify OTPs

What an Email Verification API Actually Does

An email verification API handles the boring but critical part of user onboarding: confirming that a person controls the inbox they typed into your signup form. Instead of building your own SMTP pipeline, managing bounce logs, and hand-rolling one-time password logic, you call a REST endpoint. The API sends a code, stores its state, and tells you whether the code the user entered is correct.

There are two related jobs here, and it helps to separate them early:

  • Deliverability verification confirms the address is real and can receive mail before you send anything.
  • OTP verification sends a one-time code to that address and checks the user's input.

Most teams need both. You want to reject typos and disposable addresses at signup, then prove ownership with a code. This guide focuses on the OTP flow while touching on how the two fit together.

Developer looking at API request and response on a code editor

Why Use an API Instead of Rolling Your Own

Sending a single email is easy. Sending reliable, verifiable, rate-limited emails at scale is not. When you build the flow yourself, you inherit a long list of edge cases.

  • Bounces and blocklists. A raw SMTP setup with poor reputation lands in spam. An API abstracts sender reputation for you.
  • State management. You need to store each code, its expiry, its attempt count, and tie it to a session safely.
  • Retry and rate limits. Abusers will hammer your send endpoint. Someone has to throttle that.
  • Localization. Codes and templates in multiple languages add complexity fast.

A good API collapses these concerns into two calls. SMSBulk exposes an email verification API that mirrors its SMS verification endpoints, so if you already receive SMS codes through the same account, the mental model is identical. One wallet, one auth token, two channels.

The Two-Endpoint Model

Almost every OTP-by-email API reduces to two operations. Naming varies, but the shape is consistent.

1. Request a code

You send the target email address and, optionally, metadata like a template ID or locale. The API generates a code, emails it, and returns a request identifier you keep on your side.

POST /api/email/otp/send
Content-Type: application/json
Authorization: Bearer YOUR_API_KEY

{
  "email": "[email protected]",
  "locale": "en",
  "ttl": 300
}

A typical response:

{
  "request_id": "otp_9f2a7c",
  "status": "sent",
  "expires_in": 300
}

Store that request_id against the user's session. Never trust the client to hold the raw code.

2. Verify the code

When the user pastes the code, you send the request_id plus their input. The API compares, decrements the attempt counter, and returns a verdict.

POST /api/email/otp/verify
Content-Type: application/json
Authorization: Bearer YOUR_API_KEY

{
  "request_id": "otp_9f2a7c",
  "code": "482915"
}

Response:

{
  "request_id": "otp_9f2a7c",
  "status": "verified"
}

On failure you get a status like invalid_code, expired, or too_many_attempts. Handle each distinctly in your UI so users know whether to retry or request a new code.

A Minimal Integration in Code

Here is a compact Node.js example wiring both calls together. The same pattern applies in Python, Go, or PHP.

const API = 'https://api.smsbulk.net';
const KEY = process.env.SMSBULK_KEY;

async function sendCode(email) {
  const res = await fetch(`${API}/api/email/otp/send`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      Authorization: `Bearer ${KEY}`,
    },
    body: JSON.stringify({ email, ttl: 300 }),
  });
  return res.json(); // { request_id, status }
}

async function verifyCode(requestId, code) {
  const res = await fetch(`${API}/api/email/otp/verify`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      Authorization: `Bearer ${KEY}`,
    },
    body: JSON.stringify({ request_id: requestId, code }),
  });
  return res.json(); // { status }
}

Keep the request_id server-side, tied to the session. The browser only ever sends the six digits the user typed. If you want a deeper walkthrough with full request and response cycles, the guide on how to receive email OTP codes in code covers the same flow end to end.

Flow diagram showing send code and verify code steps between app and API

Security Practices You Should Not Skip

OTP flows fail quietly when built carelessly. A working demo can still be trivially bypassed. Bake these rules in from the start.

Enforce expiry and short TTLs

Codes should live minutes, not hours. A five-minute window balances usability against brute-force risk. Once expired, the code is dead server-side, not just hidden in the UI.

Limit attempts per code

Allow three to five guesses, then invalidate the code entirely. Without this, a six-digit code is guessable in seconds by an automated script.

Rate-limit the send endpoint

One user should not trigger dozens of emails per minute. Throttle by IP, by account, and by target address. This protects both your reputation and the recipient's inbox.

Never log the raw code

Codes in application logs are a leak waiting to happen. Log the request_id and outcome, never the digits.

Compare in constant time

Use a constant-time comparison for the code check to avoid timing side channels. Most API providers do this internally, but if you ever verify locally, do not use a naive string equality.

Email OTP vs SMS OTP: Choosing a Channel

Email and SMS solve overlapping problems with different trade-offs. Email is cheaper and needs no phone number. SMS is faster to reach a device and harder to abuse with disposable inboxes. Many products offer both and let the user pick, or use email for signup and SMS for high-risk actions like password resets.

If you are weighing the two, the comparison of SMS OTP vs email OTP breaks down latency, cost, and security for each. The practical answer for most apps: email for account creation, SMS for step-up authentication.

Because SMSBulk runs both channels behind one API and one wallet, you can start with email and add phone verification later without a second vendor contract. The SMS verification service uses the same authentication scheme, so your integration code barely changes.

Handling Deliverability Before You Send

Sending an OTP to an invalid or disposable address wastes money and hurts your sender score. A verification step before the OTP catches most of these.

  • Syntax check. Reject malformed addresses client-side and server-side.
  • Domain and MX check. Confirm the domain exists and accepts mail.
  • Disposable detection. Flag known throwaway domains at signup.

Running this filter first means your OTP send rate stays clean, bounces drop, and legitimate users get their codes reliably. Treat verification and OTP as a pipeline: validate, then send, then verify ownership.

Common Errors and How to Debug Them

When an integration misbehaves, the cause is usually one of a handful of things.

  • Code never arrives. Check spam placement first, then confirm the send call returned sent and not a soft error. Deliverability, not the API, is the usual culprit.
  • Always invalid_code. You are likely verifying against the wrong request_id, or the user is on a stale session. Log the pairing.
  • expired too soon. Your TTL is too short, or clock skew is affecting comparisons. Use server time for everything.
  • Rate-limit rejections. Legitimate retries are hitting your throttle. Add a visible cooldown timer in the UI so users do not spam the button.

Good observability turns these into quick fixes. Log the request_id, the status, and a timestamp for every send and verify call. The developer documentation lists the full set of status codes and error shapes so you can map them in your handler.

Best Practices Checklist

Before you ship, run through this list.

  • Codes are six digits or more and randomly generated server-side.
  • TTL is short and enforced server-side, not just visually.
  • Attempts per code are capped, then the code is invalidated.
  • Send and verify endpoints are both rate-limited.
  • The raw code never appears in logs or client storage.
  • Users get distinct messages for expired, wrong, and rate-limited states.
  • A resend option exists with a cooldown.
  • Deliverability is checked before sending where it matters.

Tick every box and your email OTP flow will be secure, fast, and pleasant to use.

Get Started with SMSBulk

SMSBulk gives you email OTP sending and verification through a clean REST API, backed by the same account and wallet as its SMS verification numbers and travel eSIMs. You get consistent endpoints, transparent pricing, and one integration that grows from email to SMS when you need it. Create an account, drop in your API key, and wire up the two-call flow from this guide in an afternoon. Start building with the email verification API today and ship a verification experience your users trust.

#email verification#otp#api#developers#authentication

Ready to verify accounts the easy way?

Get instant SMS codes from 190+ countries in under 30 seconds.

Related Articles