Email Verification Webhook Integration: Real-Time Notifications Guide
API calls are great until they're not. You send a verification request, wait for the response, hope nothing times out, and repeat this dance thousands of times. For high-volume applications, this request-response model becomes a bottleneck.
Webhooks solve this. Instead of your application constantly checking "is it done yet?", the verification service notifies you the instant verification completes. Your app does other things while waiting. Resources are freed up. Response times improve. Everything scales better.
Let me show you how to implement this properly.
What Are Webhooks and Why Use Them
A webhook is a reverse API call. Instead of you calling the API and waiting for a response, you give the API a URL endpoint on your server. When something happens (like verification completing), the API makes an HTTP POST request to your endpoint with the results.
Think of it like this: standard APIs are like making phone calls and staying on the line until the other person answers. Webhooks are like text messages - you send your request, go do other things, and get notified when there's a response.
For email verification, webhooks are particularly valuable because verification times vary dramatically. A simple syntax check takes milliseconds. Full SMTP verification can take 1-30 seconds depending on the mail server. Some checks require retries due to greylisting, which means waiting minutes.
With webhooks, your application doesn't care. Send the verification request, provide your webhook URL, and move on. When verification completes, you get a POST request with the results.
Basic Webhook Implementation
Here's how to set up a webhook endpoint to receive verification results.
PHP Webhook Endpoint
<?php
// webhook-endpoint.php
// This receives POST requests from BulkEmailChecker
// Get the POST payload
$payload = file_get_contents('php://input');
$data = json_decode($payload, true);
// Verify webhook signature for security
$signature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
$secret = 'your_webhook_secret';
$expected = hash_hmac('sha256', $payload, $secret);
if(!hash_equals($expected, $signature)) {
http_response_code(401);
exit('Invalid signature');
}
// Process the verification result
$email = $data['email'];
$status = $data['status'];
$event = $data['event'];
if($status === 'passed') {
// Email is valid
update_user_email_status($email, 'verified');
} elseif($status === 'failed') {
// Email is invalid
update_user_email_status($email, 'invalid');
log_reason($email, $event);
} else {
// Status is unknown (catch-all, greylisting, etc)
update_user_email_status($email, 'unknown');
}
// Always respond with 200 OK
http_response_code(200);
echo json_encode(['received' => true]);
?>Python Webhook Endpoint
from flask import Flask, request, jsonify
import hmac
import hashlib
app = Flask(__name__)
WEBHOOK_SECRET = 'your_webhook_secret'
@app.route('/webhook/verification', methods=['POST'])
def verification_webhook():
# Get the payload
payload = request.get_data()
signature = request.headers.get('X-Webhook-Signature', '')
# Verify signature
expected = hmac.new(
WEBHOOK_SECRET.encode(),
payload,
hashlib.sha256
).hexdigest()
if not hmac.compare_digest(expected, signature):
return jsonify({'error': 'Invalid signature'}), 401
# Parse the data
data = request.get_json()
email = data['email']
status = data['status']
# Process based on status
if status == 'passed':
update_email_status(email, 'verified')
elif status == 'failed':
update_email_status(email, 'invalid')
else:
update_email_status(email, 'unknown')
return jsonify({'received': True}), 200
if __name__ == '__main__':
app.run()Node.js Webhook Endpoint
const express = require('express');
const crypto = require('crypto');
const app = express();
const WEBHOOK_SECRET = 'your_webhook_secret';
app.post('/webhook/verification', express.raw({type: 'application/json'}), (req, res) => {
const signature = req.headers['x-webhook-signature'];
const payload = req.body;
// Verify signature
const expected = crypto
.createHmac('sha256', WEBHOOK_SECRET)
.update(payload)
.digest('hex');
if(signature !== expected) {
return res.status(401).json({error: 'Invalid signature'});
}
// Parse the payload
const data = JSON.parse(payload.toString());
const {email, status, event} = data;
// Process the result
if(status === 'passed') {
updateEmailStatus(email, 'verified');
} else if(status === 'failed') {
updateEmailStatus(email, 'invalid');
} else {
updateEmailStatus(email, 'unknown');
}
res.status(200).json({received: true});
});
app.listen(3000);Webhook Security Best Practices
Webhooks create a security consideration: anyone who knows your webhook URL can send fake requests to it. You need to verify that requests actually come from BulkEmailChecker.
HMAC Signature Verification
BulkEmailChecker signs every webhook request with an HMAC-SHA256 signature. The signature is sent in the X-Webhook-Signature header. You verify it by computing the HMAC of the raw request body using your webhook secret.
This ensures the request came from BulkEmailChecker and hasn't been tampered with.
Additional Security Measures
Beyond signature verification, implement these security practices:
- HTTPS only - Never use HTTP for webhooks. Always use HTTPS to encrypt data in transit.
- IP whitelist - Restrict webhook endpoint to accept requests only from BulkEmailChecker's IP addresses.
- Rate limiting - Implement rate limiting to prevent webhook flooding attacks.
- Idempotency - Handle duplicate webhook deliveries gracefully by checking if you've already processed this verification.
Understanding Webhook Payloads
The webhook POST request includes the complete verification result in JSON format. Here's what you'll receive:
{
"email": "user@example.com",
"status": "passed",
"event": "mailbox_exists",
"details": "Mailbox exists and is accepting mail",
"isDisposable": false,
"isFreeService": true,
"isRoleAccount": false,
"domain": "example.com",
"timestampUTC": "2026-02-05T14:30:00Z",
"execution": "1.23",
"webhookId": "wh_abc123def456"
}Key fields explained:
- status - Overall result: "passed", "failed", or "unknown"
- event - Specific reason: "mailbox_exists", "mailbox_does_not_exist", "is_catchall", etc.
- isDisposable - Boolean flag for temporary email addresses
- isFreeService - Boolean flag for Gmail, Yahoo, etc.
- isRoleAccount - Boolean flag for info@, sales@, etc.
- webhookId - Unique ID for this webhook delivery (use for idempotency)
For complete field documentation, see the BulkEmailChecker API reference.
Webhook Retry and Failure Handling
Webhooks can fail. Your server might be temporarily down, experiencing high load, or having network issues. BulkEmailChecker automatically retries failed webhook deliveries.
Automatic Retry Schedule
If your endpoint doesn't respond with HTTP 200 within 10 seconds, the webhook is retried:
- Attempt 1: Immediate
- Attempt 2: After 1 minute
- Attempt 3: After 5 minutes
- Attempt 4: After 15 minutes
- Attempt 5: After 1 hour
After 5 failed attempts, the webhook delivery is marked as failed and you'll need to manually retrieve the result.
Implementing Idempotent Webhook Handling
Because of retries, your endpoint might receive the same webhook multiple times. Handle this gracefully:
<?php
function handle_webhook_idempotent($data) {
$webhook_id = $data['webhookId'];
// Check if we've already processed this webhook
if(webhook_already_processed($webhook_id)) {
// Already handled - just return success
return true;
}
// Process the webhook
$email = $data['email'];
$status = $data['status'];
// Begin transaction
db_begin_transaction();
try {
// Update email status
update_email_status($email, $status);
// Mark webhook as processed
mark_webhook_processed($webhook_id);
db_commit();
return true;
} catch(Exception $e) {
db_rollback();
throw $e;
}
}
?>Testing Webhooks Locally
Testing webhooks during development is tricky because your local server isn't publicly accessible. Here are solutions:
Using ngrok for Local Testing
Ngrok creates a public URL that tunnels to your localhost:
# Start your local server on port 3000
php -S localhost:3000
# In another terminal, start ngrok
ngrok http 3000
# Use the ngrok URL as your webhook endpoint
# Example: https://abc123.ngrok.io/webhook/verificationNow you can configure this ngrok URL as your webhook endpoint and test locally.
Manual Webhook Testing
You can also manually trigger test webhooks using curl:
curl -X POST https://yourdomain.com/webhook/verification \
-H "Content-Type: application/json" \
-H "X-Webhook-Signature: test_signature" \
-d '{
"email": "test@example.com",
"status": "passed",
"event": "mailbox_exists",
"webhookId": "test_wh_123"
}'Production Deployment Considerations
When deploying webhooks to production, keep these considerations in mind.
Webhook Endpoint Performance
Your webhook endpoint should respond quickly (under 1 second ideally). If processing takes longer:
- Immediately acknowledge receipt (return 200 OK)
- Queue the data for background processing
- Process asynchronously
Don't make your webhook endpoint do heavy work synchronously. The API will timeout and retry if you take too long to respond.
Scaling Webhook Handlers
For high-volume applications, use a queue-based architecture:
<?php
// Webhook endpoint - fast response
function webhook_endpoint() {
$payload = file_get_contents('php://input');
// Verify signature (fast)
if(!verify_signature($payload)) {
http_response_code(401);
return;
}
// Push to queue (fast) - Redis, RabbitMQ, SQS, etc.
queue_push('verification_webhooks', $payload);
// Immediate response
http_response_code(200);
echo json_encode(['queued' => true]);
}
// Separate worker process handles the queue
function worker_process() {
while(true) {
$payload = queue_pop('verification_webhooks');
if($payload) {
process_verification_result($payload);
}
sleep(1);
}
}
?>Monitoring and Debugging Webhooks
Track these metrics to ensure your webhook integration is healthy:
- Success rate - Percentage of webhooks that receive 200 OK on first attempt
- Response time - How quickly your endpoint responds
- Retry frequency - How often webhooks need to be retried
- Processing lag - Time between webhook receipt and data processing completion
Webhook Logging
Log all webhook receipts for debugging:
<?php
function log_webhook($data, $success) {
$log_entry = [
'timestamp' => date('Y-m-d H:i:s'),
'webhook_id' => $data['webhookId'],
'email' => $data['email'],
'status' => $data['status'],
'success' => $success,
'ip' => $_SERVER['REMOTE_ADDR']
];
// Log to database or file
file_put_contents(
'/var/log/webhooks.log',
json_encode($log_entry) . "\n",
FILE_APPEND
);
}
?>Frequently Asked Questions
What happens if my webhook endpoint is down?
BulkEmailChecker will automatically retry the webhook delivery up to 5 times over the course of an hour. If all retries fail, you can manually retrieve the verification result using the API by querying the original request ID.
Can I use the same webhook URL for multiple verification requests?
Yes, absolutely. Your webhook endpoint should be designed to handle all verification results. Use the email address or a custom identifier in your original request to route the webhook data to the correct record in your system.
How do I test webhooks without exposing my development server?
Use ngrok or a similar tunneling service to create a temporary public URL that forwards to your localhost. Alternatively, deploy a staging environment with a public URL specifically for webhook testing.
Should I respond to the webhook before or after processing the data?
Respond immediately with 200 OK, then process the data asynchronously. This prevents timeouts and retries. Queue the webhook payload and process it in a background worker.
Conclusion
Webhooks transform email verification from a blocking operation into an efficient, scalable process. Your application submits verification requests without waiting for results, processes other tasks, and receives instant notifications when verification completes.
The key to successful webhook implementation is security (verify signatures), reliability (handle retries idempotently), and performance (respond quickly and process asynchronously).
Start by implementing a basic webhook endpoint with signature verification. Test it locally using ngrok. Deploy to production with queue-based processing for scale. Monitor success rates and response times to ensure reliability.
For complete webhook documentation and code examples, check the BulkEmailChecker API docs. Ready to get started? Try the free email verification tool to see verification in action, then integrate webhooks for production-scale applications with unlimited API pricing.
Stop Bouncing. Start Converting.
Millions of emails verified daily. Industry-leading SMTP validation engine.