Verify Email Deliverability in PHP

Assume you have a list of subscribers you send news letters to every week. But what if half of the subscribers have changed their email accounts. In this post I am going to demonstrate how to verify if an email is fake or real.

Verify Email Deliverability in PHP

Successful email delivery is important to keep a good reputation and bounce rate in control. It ensures every email is delivered to a real user. We are going to take an email retrieve the hostname from email. Next we search for MX Records against that hostname. If we find MX Records we loop through every record and send commands to SMTP server.


  1. HELO: This is the first command which tells the SMTP server a new conversation is about to start.
  2. MAIL FROM: We tell SMTP server the senders email, the source email address which is going to start conversation.
  3. RCPT TO: This command tells the SMPT server the target or receiver email address of conversation.
  4. QUIT: Tells the SMTP server to close conversation.

Lets get started we create index.html file which contains a form to receive email we then send an ajax request to validate-email.php which will open a connection to SMTP server, validate the email and send back a json response.


index.html

<!DOCTYPE html>
<html>
<head>
<title>Verify Email Deliverability in PHP - Demo</title>
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/>
<script type="text/javascript" src="js/jquery-3.1.1.min.js"></script>
<script type="text/javascript" src="js/javascript.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"/>
<link rel="stylesheet" href="css/style.css" />
</head>
<body>
<div class="container">
<div class="section">
<label class="inline-block mb-2">Enter an email to validate</label>
<form class="email-form">
<div class="input-group mb-4">
<div class="loader">
<i class="fa fa-spinner fa-spin"></i>
</div>
<input type="email" class="form-control email-input" value="" required="required" placeholder="Enter an email to validate" />
<button type="submit" class="btn btn-green">Validate</button>
</div>
</form>
<div class="content-wrapper" id="content-wrapper"></div>
</div>
</div>
</body>
</html>

validate-email.php

<?php
// Initial response as a fallback
$res['success'] = 0;
$res['status'] = 'UNKNOWN_ERROR';

if($_POST){
// Check if email was submitted
if( !isset($_POST['email']) ){
$res['status'] = 'MISSING_EMAIL';
}

$email = $_POST['email'];

// Check if email format
$valid_format = filter_var($email, FILTER_VALIDATE_EMAIL);

// If email format is correct proceed to validation check
if($valid_format){

// Get hostname from email
$hostname = substr($email, strpos($email, '@') + 1);
$mxhosts = $mxweights = [];

// Get MX-Records of hostname
$mxr = getmxrr($hostname, $mxhosts, $mxweights);
$mxr_list = array_combine($mxweights, $mxhosts);

// If MX-Records were found proceed to socket connection
if( !empty($mxr_list) ){
// Sort MX-Records by priority
krsort($mxr_list, SORT_NUMERIC);

$res['status'] = 'INVALID_EMAIL';

// Loop through all MX-Records
foreach($mxr_list as $mxweight => $mxhost){
$connection = @fsockopen($mxhost, 25, $errno, $errstr, 5);

// If connection was successful send commands to email server
if($connection){

// Send Helo command to initiate conversation
fwrite($connection, "HELO $mxhost\r\n");
$response = fgets($connection, 1024) . "\r\n";

// Send Mail From command to specify senders email
fwrite($connection, "MAIL FROM: <[email protected]> \r\n");
$response = fgets($connection, 1024) . "\r\n";

// Send RCPT TO command to specify receiver's email on server
fwrite($connection, "RCPT TO: <$email> \r\n");
$response = fgets($connection, 1024) . "\r\n";

// Send QUIT command to close conversation
fwrite($connection, "QUIT \r\n");
$response = fgets($connection, 1024);

fclose($connection);

// If last reponse returned 250 its a valid email
if( substr($response, 0, 3) == 250 ){
$res['success'] = 1;
$res['status'] = 'EMAIL_VALID';
$res['mx_hosts'] = $mxr_list;

break;
}
}
}
}else{
// No MX-Records found
$res['status'] = 'EMAIL_SERVER_NOT_FOUND';
}
}else{
// Invalid email format
$res['status'] = 'INVALID_FORMAT';
}
}
echo json_encode($res, JSON_PRETTY_PRINT);

javascript.js

$(document).ready(function(){
$(".email-form").on("submit",function(e){
e.preventDefault();
var email = $(".email-input").val();
if(email != ""){
$(".loader").show();
$.ajax({
url: "validate-email.php",
type: "POST",
data:{
email: email,
},
success: function(res){
$(".loader").hide();
$(".content-wrapper").html( '<pre>' + res + '</pre>' );
}
});
}
});
});

style.css

*{
box-sizing: border-box;
}
html,body{
margin: 0;
padding: 0;
}
body{
background-color: #f6f6f6;
font-family: "Segoe UI", "Roboto", "Helvetica", sans-serif;
font-size: 15px;
font-weight: normal;
font-style: normal;
}
a{
text-decoration: none;
color: #3778cd;
}
.container{
width: 100%;
max-width: 1140px;
margin-right: auto;
margin-left: auto;
padding-right: 15px;
padding-left: 15px;
}
.inline-block {
display: inline-block;
}
.my-2, .mb-2 {
margin-bottom: 0.5rem;
}
.my-4, .mb-4 {
margin-bottom: 1rem;
}
.input-group {
position: relative;
display: flex;
flex-wrap: wrap;
align-items: stretch;
width: 100%;
}
.form-control{
display: block;
width: 100%;
padding: .375rem .75rem;
font-size: 1rem;
font-weight: 400;
line-height: 1.5;
color: #3b3b3b;
background-color: #ffffff;
background-clip: padding-box;
border: 1px solid #d1d2d3;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
transition: border-color .15s ease-in-out,box-shadow .15s ease-in-out;
}
.input-group > .form-control{
position: relative;
flex: 1 1 auto;
width: 1%;
min-width: 0;
}
.btn {
display: inline-block;
padding: 5px 10px;
cursor: pointer;
font: inherit;
}
.btn-green {
background-color: #319764;
border: 1px solid #248A57;
color: #ffffff;
}
.input-group .btn {
position: relative;
z-index: 2;
margin-left: -1px;
}
.loader{
position: absolute;
font-size: 25px;
background: rgba(150,150,150,0.5);
width: 100%;
height: 100%;
z-index: 5;
padding: 0 10px;
display: none;
color: #006699;
text-align: center;
}
.content-wrapper pre{
background-color: #fff;
border: 1px solid #ddd;
padding: 15px;
}