Check Email Deliverability in PHP

Assume you have a list of subscribers you send news letters to every week. But what if half of the email accounts of those subscribers do not exist anymore? This post demonstrates how to check if an email address is valid in PHP before sending out emails.

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. You can find out if an email address exist by checking MX records of an email address and connecting with mail server to send some commands. In this post we are going to learn how to check if an email address is real to receive emails. We are going to create following files for this post:

  1. index.html: The HTML page containing email field form.
  2. validate-email.php: The server side PHP code to process provided email.
  3. javascript.js: The Javascript code to submit form via AJAX.
  4. style.css: CSS styles for HTML page.

Why It is Important to Check if Email is Valid

When you are sending emails in large number to fake addresses it affects your email server's sender reputation. You should check if email is real or fake before sending out emails to save resources and risk of being marked as spam. 


How to Check if an Email Address Exists

It is very easy to check if an email address exists with simple steps in PHP. We get MX records of domain in PHP and attempt a connection with MX servers of domain. Then we send some SMTP commands to with recipient's email to check if mailbox exists. You can use following SMTP commands to check if an email is real or fake.

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

Lets get started and start working with our code implementation.

 

HTML Form with Email Field for Validation

Create an HTML page with email input field form to send validate.

index.html

<!DOCTYPE html>
<html>
<head>
<title>Check 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>

Submit Email Field Form via AJAX

Submit the email address form via jQuery AJAX to server side PHP code for processing email for validation.

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>' );
}
});
}
});
});
 

Check Email Deliverability

Create a PHP script file to verify if email address exists and can receive emails to verify email deliverability. Follow these steps to check an email address exists.

  • Set initial response to UNKNOWN_ERROR.
  • Check if form data was submitted and $_POST variable is not empty.
  • Check if email was send in form data.
  • Check if email address is in valid email format. 
  • Get MX records of email domain using getmxrr() function.
  • Open a connection with MX server for each MX record.
  • Send SMTP commands to mail server using fwrite() function and capture server response using fgets(). The response code 250 means email address exists.
  • Finally return the response in pretty JSON format.

validate-email.php

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

if(!empty($_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 response 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);

ADD CSS Styles

Add CSS styles for entire HTML page and email address form.

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;
}