Every app needs email verification. The standard approach? Send an OTP, wait for the user to receive it, hope it doesn't land in spam.
But what if users could prove they own their email without you sending anything?
I built Sendovate to solve this. Here's how the "reversal method" works and why it might save you money and headaches.
The Problem with Traditional OTP Verification
When a user signs up, most apps:
- Generate a code
- Send an email (costs money)
- Wait for delivery (sometimes slow)
- Hope it doesn't hit spam
- User copies code back
Every email you send costs money. SMS OTPs cost even more. And deliverability issues mean some users never receive their codes.
The Reversal Method
What if we flip the flow?
Instead of you sending TO the user, the user sends TO you.
Here's how it works:
- User clicks "Verify my email"
- Your app calls Sendovate API → gets a unique code and verification email address
- User sends any email to that address (one click from their mail client)
- Sendovate receives it and confirms ownership
- You check the status or receive a webhook → user is verified
The result:
- No deliverability issues
- Works with any email provider
- User proves ownership by action
Quick Implementation
Step 1: Request a reversal verification
curl -X POST https://sendovate.com/api/v1/otp/reversal/send \
-H "X-API-Key: sk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"purpose": "signup"
}'
Response:
{
"success": true,
"data": {
"otp_id": 12346,
"code": "ABC123",
"send_to": "verify-abc123@inbound.sendovate.com",
"expires_at": "2025-01-15T10:30:00Z"
}
}
Step 2: Show the user what to do
Display a button that opens their email client:
<a href="mailto:verify-abc123@inbound.sendovate.com?subject=ABC123">
Click to verify your email
</a>
Or show instructions: "Send any email to verify-abc123@inbound.sendovate.com with subject ABC123"
Step 3: Check if verified
Poll the status :
curl -X POST https://sendovate.com/api/v1/otp/reversal/check \
-H "X-API-Key: sk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"email": "user@example.com",
"code": "ABC123"
}'
Response when verified:
{
"success": true,
"data": {
"verified": true,
"verified_at": "2025-01-15T10:25:00Z"
}
}
Done. Email ownership confirmed.
What About Disposable Emails?
Reversal verification solves ownership, but what about users signing up with throwaway emails like temp123@guerrillamail.com?
Sendovate also includes email validation:
curl -X POST https://sendovate.com/api/v1/email/validate \
-H "X-API-Key: sk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{"email": "user@guerrillamail.com"}'
Response:
{
"success": true,
"data": {
"email": "user@guerrillamail.com",
"valid": false,
"disposable": true,
"risk_score": 95,
"reason": "Disposable email domain"
}
}
Block fake signups before they even start.
Need to Validate in Bulk?
Validate up to 100 emails in one request:
curl -X POST https://sendovate.com/api/v1/email/validate/bulk \
-H "X-API-Key: sk_live_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"emails": [
"user1@gmail.com",
"fake@tempmail.com",
"user2@company.com"
]
}'
Or upload a CSV file for batch processing up to 100,000 emails:
curl -X POST https://sendovate.com/api/v1/email/batch \
-H "X-API-Key: sk_live_your_api_key" \
-F "file=@emails.csv"
Full Code Example (Node.js)
const axios = require('axios');
const apiKey = 'sk_live_your_api_key';
const baseUrl = 'https://sendovate.com/api/v1';
// Step 1: Validate email first (block disposables)
async function validateEmail(email) {
const response = await axios.post(`${baseUrl}/email/validate`,
{ email },
{ headers: { 'X-API-Key': apiKey } }
);
return response.data;
}
// Step 2: Start reversal verification
async function startReversal(email) {
const response = await axios.post(`${baseUrl}/otp/reversal/send`,
{ email, purpose: 'signup' },
{ headers: { 'X-API-Key': apiKey } }
);
return response.data;
}
// Step 3: Check if verified
async function checkReversal(email, code) {
const response = await axios.post(`${baseUrl}/otp/reversal/check`,
{ email, code },
{ headers: { 'X-API-Key': apiKey } }
);
return response.data;
}
// Usage
async function verifyUser(email) {
// First, check if email is valid
const validation = await validateEmail(email);
if (validation.data.disposable) {
throw new Error('Disposable emails not allowed');
}
// Start reversal verification
const reversal = await startReversal(email);
console.log(`Ask user to email: ${reversal.data.send_to}`);
console.log(`With subject: ${reversal.data.code}`);
return reversal.data;
}
When to Use Which Method
| Scenario | Use |
|---|---|
| Block disposable/fake emails | Email Validation |
| Verify ownership (user action OK) | Reversal Method |
| Verify ownership (seamless UX) | Standard OTP |
| High-security apps | Validation + Reversal |
| Clean existing email list | Batch Validation |
Pricing
- Email Validation: 1 SVC per email
- Reversal Verification: 1 SVC per verification
- Standard OTP: 1 SVC per OTP
No monthly minimums. Pay for what you use.
Try It
I just launched this and would love feedback from the dev community.
The API docs have full details, and there's a Postman collection if you want to test quickly.
What's your current email verification setup? Ever had OTP deliverability issues? I'd love to hear your experiences.
Top comments (0)