Email Validation API for Firebase
Validate email addresses in Cloud Functions before Firebase Auth creates the account. Block typos, disposable addresses, and invalid mailboxes at the door.
Contents
Firebase Authentication handles user signup and session management, but it does not validate whether an email address is real and deliverable. Users can register with typos (user@gmial.com), disposable addresses, or completely fabricated inboxes. These phantom accounts consume your Firebase Auth quota, pollute your user table, and skew engagement metrics.
This guide shows how to integrate the MailOdds email validation API with Firebase Cloud Functions to verify addresses before account creation. You will build a callable Cloud Function, wire it into your client-side signup flow, and optionally add a Blocking Function for server-side enforcement.
Why Validate Before Firebase Auth Creates the Account?
Firebase Auth accepts any syntactically valid email string. Its built-in email verification only confirms the user can receive mail after the account already exists. That leaves several gaps:
- Quota waste — every invalid account counts against your Firebase Auth monthly active users.
- Disposable signups — throwaway addresses from Mailinator, Guerrilla Mail, and similar services create users who never engage.
- Typo signups — common mistakes like
@gnail.comor@yaho.comlock real users out of their own accounts. - Cleanup cost — it is cheaper to prevent a bad signup than to detect and purge it later.
Step 1: Set Up Cloud Functions
Initialize Firebase Cloud Functions in your project and install the MailOdds TypeScript SDK. If you already have Cloud Functions configured, skip to the install step.
npm install firebase-functions firebase-admin mailoddsConfigure the MailOdds client with your API key. Store the key in Firebase environment config so it stays out of source control:
firebase functions:config:set mailodds.api_key="YOUR_API_KEY"Then initialize the client in your functions entry point:
// functions/src/index.ts
import * as functions from 'firebase-functions';
import { MailOdds } from 'mailodds';
const client = new MailOdds({
apiKey: functions.config().mailodds.api_key,
baseUrl: 'https://api.mailodds.com'
});Get your API key from the dashboard. The free tier includes 50 validations per month with no credit card required.
Step 2: Create the Validation Cloud Function
Create a callable Cloud Function that accepts an email address, validates it through the MailOdds API, and returns a structured result. The function uses a fail-open pattern: if the validation service is unreachable, the signup proceeds rather than blocking a legitimate user.
// functions/src/index.ts
export const validateEmail = functions.https.onCall(
async (data, context) => {
const { email } = data;
if (!email || typeof email !== 'string') {
throw new functions.https.HttpsError(
'invalid-argument',
'Email is required'
);
}
try {
const result = await client.validate({
email: email.trim().toLowerCase()
});
return {
valid: result.action === 'accept',
action: result.action,
status: result.status,
sub_status: result.sub_status,
disposable: result.disposable,
did_you_mean: result.did_you_mean,
};
} catch (error) {
// Fail open: allow signup if validation is unreachable
console.error('Email validation failed:', error);
return {
valid: true,
action: 'accept',
status: 'unknown',
sub_status: 'service_unavailable',
disposable: false,
did_you_mean: null,
};
}
}
);Fail-open pattern
If the MailOdds API is unreachable (network issue, timeout, or outage), the function returns valid: true so real users are never blocked. You can flag these signups for later review by checking the service_unavailable sub-status.
Step 3: Client-Side Integration
Call the Cloud Function from your web or mobile app before creating the Firebase Auth account. This lets you show helpful feedback (typo suggestions, disposable email warnings) directly in the signup form.
// Web client (React, Next.js, or vanilla)
import { getFunctions, httpsCallable } from 'firebase/functions';
import {
getAuth,
createUserWithEmailAndPassword,
sendEmailVerification
} from 'firebase/auth';
const functions = getFunctions();
const validateEmail = httpsCallable(functions, 'validateEmail');
const auth = getAuth();
async function handleSignup(email: string, password: string) {
// Step 1: Validate the email
const { data } = await validateEmail({ email });
if (!data.valid) {
if (data.did_you_mean) {
showError(`Did you mean ${data.did_you_mean}?`);
} else if (data.disposable) {
showError('Please use a permanent email address.');
} else {
showError('This email address appears to be invalid.');
}
return;
}
// Step 2: Create the Firebase Auth account
try {
const userCredential = await createUserWithEmailAndPassword(
auth, email, password
);
await sendEmailVerification(userCredential.user);
} catch (error) {
showError('Signup failed. Please try again.');
}
}The did_you_mean field catches common typos. When a user types user@gmial.com, the API suggests user@gmail.com, giving the user a chance to correct the mistake before creating their account.
Step 4: Blocking Function Alternative
Firebase also supports Blocking Functions that execute before account creation at the Firebase Auth level. This approach is more secure because validation happens server-side regardless of what client code does.
// functions/src/index.ts
export const validateBeforeCreate =
functions.auth.user().beforeCreate(
async (user) => {
if (!user.email) return;
try {
const result = await client.validate({
email: user.email
});
if (result.action === 'reject') {
throw new functions.auth.HttpsError(
'invalid-argument',
`Email validation failed: ${result.sub_status}`
);
}
} catch (error) {
if (error instanceof functions.auth.HttpsError)
throw error;
// Fail open for service errors
console.error('Validation service error:', error);
}
}
);Callable vs. Blocking
The callable function (Step 2) gives you rich client-side UX: typo suggestions, disposable warnings, and custom error messages. The Blocking Function (Step 4) provides server-side enforcement that cannot be bypassed. For maximum protection, use both together.
Handling Edge Cases
A few scenarios require special handling in production:
Catch-all domains
Some mail servers accept all incoming addresses regardless of whether the mailbox exists. These return a catch_all status. Consider allowing them but flagging the account for review, since you cannot confirm deliverability with certainty.
Rate limits
The MailOdds API returns a 429 status with a Retry-After header when you exceed your plan limit. Implement exponential backoff in your Cloud Function, or let the SDK handle retries automatically.
Function timeouts
Cloud Functions have a default timeout of 60 seconds. Email validation typically completes in under 3 seconds, but set a reasonable function timeout and ensure your fail-open logic handles the case where validation takes too long.
Cost management
The free tier includes 50 validations per month. For higher volumes, check the pricing page. Each unique email is cached for 24 hours, so re-validating the same address does not consume additional credits.
Related Resources
Email Validation API
Full API reference and documentation.
TypeScript SDK
SDK installation and usage for all 11 languages.
Email Deliverability Guide
Comprehensive guide to improving email deliverability.
JavaScript Integration Guide
Vanilla JS, React, and Node.js validation examples.
Email Validation Glossary
30+ email validation and deliverability terms explained.
Postman Collection
Test all API endpoints with pre-configured requests.
Start validating emails in your Firebase app
50 free validations per month, no credit card required. Set up in under 5 minutes.