Verify Email Address and Check if Email is Real using PHP

Verifying the email address is a hardest but mandatory task in the web world. A valid email can help to make your marketing profitable. But an invalid email increases your marking cost and effects on the email client’s reputation. Similarly, the email validation is the common and useful functionality on the web application. Before working with the email address, it needs to be verified and checked whether the email is valid or not.

Validate email in PHP can be easily done by using filter_var() function with FILTER_VALIDATE_EMAIL filter. It will check if the format of the given email address is valid. But only this filter is not enough to check whether an email address exists. In this tutorial, we will show you how to check if an email address is real and exists using PHP.

In the PHP email verification script, we will validate an email address by checking MX DNS Record and domain. This script is very useful to verify the user’s email address before sending an email or insert in the database. You can differentiate real and invalid email address, and accept only the valid email address from the user.

PHP Email Verification Library

The VerifyEmail class is used to check if an email address is valid and real using SMTP protocol in PHP. You need to use one function of VerifyEmail class to verify the email address in PHP.

check()

  • Validate the format of the email address.
  • Get MX records of the domain of the email address.
  • Connect to the SMTP server by the MX records.
  • Based on the response code:
    • Check if given recipient email address is valid.
    • Check if the user of email’s domain exists.
    • Check the delivery of the message.
<?php 
/** 
 * Class to validate the email address 
 * 
 * @author CodexWorld.com <contact@codexworld.com> 
 * @copyright Copyright (c) 2018, CodexWorld.com
 * @url https://www.codexworld.com
 */ 
class VerifyEmail 

    protected 
$stream false

    
/** 
     * SMTP port number 
     * @var int 
     */ 
    
protected $port 25

    
/** 
     * Email address for request 
     * @var string 
     */ 
    
protected $from 'root@localhost'

    
/** 
     * The connection timeout, in seconds. 
     * @var int 
     */ 
    
protected $max_connection_timeout 30

    
/** 
     * Timeout value on stream, in seconds. 
     * @var int 
     */ 
    
protected $stream_timeout 5

    
/** 
     * Wait timeout on stream, in seconds. 
     * * 0 - not wait 
     * @var int 
     */ 
    
protected $stream_timeout_wait 0

    
/** 
     * Whether to throw exceptions for errors. 
     * @type boolean 
     * @access protected 
     */ 
    
protected $exceptions false

    
/** 
     * The number of errors encountered. 
     * @type integer 
     * @access protected 
     */ 
    
protected $error_count 0

    
/** 
     * class debug output mode. 
     * @type boolean 
     */ 
    
public $Debug false

    
/** 
     * How to handle debug output. 
     * Options: 
     * * `echo` Output plain-text as-is, appropriate for CLI 
     * * `html` Output escaped, line breaks converted to `<br>`, appropriate for browser output 
     * * `log` Output to error log as configured in php.ini 
     * @type string 
     */ 
    
public $Debugoutput 'echo'

    
/** 
     * SMTP RFC standard line ending. 
     */ 
    
const CRLF "\r\n"

    
/** 
     * Holds the most recent error message. 
     * @type string 
     */ 
    
public $ErrorInfo ''

    
/** 
     * Constructor. 
     * @param boolean $exceptions Should we throw external exceptions? 
     */ 
    
public function __construct($exceptions false) { 
        
$this->exceptions = (boolean) $exceptions
    } 

    
/** 
     * Set email address for SMTP request 
     * @param string $email Email address 
     */ 
    
public function setEmailFrom($email) { 
        if (!
self::validate($email)) { 
            
$this->set_error('Invalid address : ' $email); 
            
$this->edebug($this->ErrorInfo); 
            if (
$this->exceptions) { 
                throw new 
verifyEmailException($this->ErrorInfo); 
            } 
        } 
        
$this->from $email
    } 

    
/** 
     * Set connection timeout, in seconds. 
     * @param int $seconds 
     */ 
    
public function setConnectionTimeout($seconds) { 
        if (
$seconds 0) { 
            
$this->max_connection_timeout = (int) $seconds
        } 
    } 

    
/** 
     * Sets the timeout value on stream, expressed in the seconds 
     * @param int $seconds 
     */ 
    
public function setStreamTimeout($seconds) { 
        if (
$seconds 0) { 
            
$this->stream_timeout = (int) $seconds
        } 
    } 

    public function 
setStreamTimeoutWait($seconds) { 
        if (
$seconds >= 0) { 
            
$this->stream_timeout_wait = (int) $seconds
        } 
    } 

    
/** 
     * Validate email address. 
     * @param string $email 
     * @return boolean True if valid. 
     */ 
    
public static function validate($email) { 
        return (boolean) 
filter_var($emailFILTER_VALIDATE_EMAIL); 
    } 

    
/** 
     * Get array of MX records for host. Sort by weight information. 
     * @param string $hostname The Internet host name. 
     * @return array Array of the MX records found. 
     */ 
    
public function getMXrecords($hostname) { 
        
$mxhosts = array(); 
        
$mxweights = array(); 
        if (
getmxrr($hostname$mxhosts$mxweights) === FALSE) { 
            
$this->set_error('MX records not found or an error occurred'); 
            
$this->edebug($this->ErrorInfo); 
        } else { 
            
array_multisort($mxweights$mxhosts); 
        } 
        
/** 
         * Add A-record as last chance (e.g. if no MX record is there). 
         * Thanks Nicht Lieb. 
         * @link http://www.faqs.org/rfcs/rfc2821.html RFC 2821 - Simple Mail Transfer Protocol 
         */ 
        
if (empty($mxhosts)) { 
            
$mxhosts[] = $hostname
        } 
        return 
$mxhosts
    } 

    
/** 
     * Parses input string to array(0=>user, 1=>domain) 
     * @param string $email 
     * @param boolean $only_domain 
     * @return string|array 
     * @access private 
     */ 
    
public static function parse_email($email$only_domain TRUE) { 
        
sscanf($email"%[^@]@%s"$user$domain); 
        return (
$only_domain) ? $domain : array($user$domain); 
    } 

    
/** 
     * Add an error message to the error container. 
     * @access protected 
     * @param string $msg 
     * @return void 
     */ 
    
protected function set_error($msg) { 
        
$this->error_count++; 
        
$this->ErrorInfo $msg
    } 

    
/** 
     * Check if an error occurred. 
     * @access public 
     * @return boolean True if an error did occur. 
     */ 
    
public function isError() { 
        return (
$this->error_count 0); 
    } 

    
/** 
     * Output debugging info 
     * Only generates output if debug output is enabled 
     * @see verifyEmail::$Debugoutput 
     * @see verifyEmail::$Debug 
     * @param string $str 
     */ 
    
protected function edebug($str) { 
        if (!
$this->Debug) { 
            return; 
        } 
        switch (
$this->Debugoutput) { 
            case 
'log'
                
//Don't output, just log 
                
error_log($str); 
                break; 
            case 
'html'
                
//Cleans up output a bit for a better looking, HTML-safe output 
                
echo htmlentities
                        
preg_replace('/[\r\n]+/'''$str), ENT_QUOTES'UTF-8' 
                

                . 
"<br>\n"
                break; 
            case 
'echo'
            default: 
                
//Normalize line breaks 
                
$str preg_replace('/(\r\n|\r|\n)/ms'"\n"$str); 
                echo 
gmdate('Y-m-d H:i:s') . "\t" str_replace
                        
"\n""\n \t "trim($str
                ) . 
"\n"
        } 
    } 

    
/** 
     * Validate email
     * @param string $email Email address 
     * @return boolean True if the valid email also exist 
     */ 
    
public function check($email) { 
        
$result FALSE

        if (!
self::validate($email)) { 
            
$this->set_error("{$email} incorrect e-mail"); 
            
$this->edebug($this->ErrorInfo); 
            if (
$this->exceptions) { 
                throw new 
verifyEmailException($this->ErrorInfo); 
            } 
            return 
FALSE
        } 
        
$this->error_count 0// Reset errors 
        
$this->stream FALSE

        
$mxs $this->getMXrecords(self::parse_email($email)); 
        
$timeout ceil($this->max_connection_timeout count($mxs)); 
        foreach (
$mxs as $host) { 
            
/** 
             * suppress error output from stream socket client... 
             * Thanks Michael. 
             */ 
            
$this->stream = @stream_socket_client("tcp://" $host ":" $this->port$errno$errstr$timeout); 
            if (
$this->stream === FALSE) { 
                if (
$errno == 0) { 
                    
$this->set_error("Problem initializing the socket"); 
                    
$this->edebug($this->ErrorInfo); 
                    if (
$this->exceptions) { 
                        throw new 
verifyEmailException($this->ErrorInfo); 
                    } 
                    return 
FALSE
                } else { 
                    
$this->edebug($host ":" $errstr); 
                } 
            } else { 
                
stream_set_timeout($this->stream$this->stream_timeout); 
                
stream_set_blocking($this->stream1); 

                if (
$this->_streamCode($this->_streamResponse()) == '220') { 
                    
$this->edebug("Connection success {$host}"); 
                    break; 
                } else { 
                    
fclose($this->stream); 
                    
$this->stream FALSE
                } 
            } 
        } 

        if (
$this->stream === FALSE) { 
            
$this->set_error("All connection fails"); 
            
$this->edebug($this->ErrorInfo); 
            if (
$this->exceptions) { 
                throw new 
verifyEmailException($this->ErrorInfo); 
            } 
            return 
FALSE
        } 

        
$this->_streamQuery("HELO " self::parse_email($this->from)); 
        
$this->_streamResponse(); 
        
$this->_streamQuery("MAIL FROM: <{$this->from}>"); 
        
$this->_streamResponse(); 
        
$this->_streamQuery("RCPT TO: <{$email}>"); 
        
$code $this->_streamCode($this->_streamResponse()); 
        
$this->_streamResponse(); 
        
$this->_streamQuery("RSET"); 
        
$this->_streamResponse();
        
$code2 $this->_streamCode($this->_streamResponse()); 
        
$this->_streamQuery("QUIT"); 
        
fclose($this->stream); 
        
        
$code = !empty($code2)?$code2:$code;
        switch (
$code) { 
            case 
'250'
            
/** 
             * http://www.ietf.org/rfc/rfc0821.txt 
             * 250 Requested mail action okay, completed 
             * email address was accepted 
             */ 
            
case '450'
            case 
'451'
            case 
'452'
                
/** 
                 * http://www.ietf.org/rfc/rfc0821.txt 
                 * 450 Requested action not taken: the remote mail server 
                 * does not want to accept mail from your server for 
                 * some reason (IP address, blacklisting, etc..) 
                 * Thanks Nicht Lieb. 
                 * 451 Requested action aborted: local error in processing 
                 * 452 Requested action not taken: insufficient system storage 
                 * email address was greylisted (or some temporary error occured on the MTA) 
                 * i believe that e-mail exists 
                 */ 
                
return TRUE;
            case 
'550':
                return 
FALSE
            default : 
                return 
FALSE
        } 
    } 

    
/** 
     * writes the contents of string to the file stream pointed to by handle 
     * If an error occurs, returns FALSE. 
     * @access protected 
     * @param string $string The string that is to be written 
     * @return string Returns a result code, as an integer. 
     */ 
    
protected function _streamQuery($query) { 
        
$this->edebug($query); 
        return 
stream_socket_sendto($this->stream$query self::CRLF); 
    } 

    
/** 
     * Reads all the line long the answer and analyze it. 
     * If an error occurs, returns FALSE 
     * @access protected 
     * @return string Response 
     */ 
    
protected function _streamResponse($timed 0) { 
        
$reply stream_get_line($this->stream1); 
        
$status stream_get_meta_data($this->stream); 

        if (!empty(
$status['timed_out'])) { 
            
$this->edebug("Timed out while waiting for data! (timeout {$this->stream_timeout} seconds)"); 
        } 

        if (
$reply === FALSE && $status['timed_out'] && $timed $this->stream_timeout_wait) { 
            return 
$this->_streamResponse($timed $this->stream_timeout); 
        } 


        if (
$reply !== FALSE && $status['unread_bytes'] > 0) { 
            
$reply .= stream_get_line($this->stream$status['unread_bytes'], self::CRLF); 
        } 
        
$this->edebug($reply); 
        return 
$reply
    } 

    
/** 
     * Get Response code from Response 
     * @param string $str 
     * @return string 
     */ 
    
protected function _streamCode($str) { 
        
preg_match('/^(?<code>[0-9]{3})(\s|-)(.*)$/ims'$str$matches); 
        
$code = isset($matches['code']) ? $matches['code'] : false
        return 
$code
    } 



/** 
 * verifyEmail exception handler 
 */ 
class verifyEmailException extends Exception 

    
/** 
     * Prettify error message output 
     * @return string 
     */ 
    
public function errorMessage() {
        
$errorMsg $this->getMessage(); 
        return 
$errorMsg
    } 



?>

Usage

The VerifyEmail library is easy to use for validating the email address using PHP.

  • Initialize the library class using VerifyEmail().
  • Set the timeout, debug, and sender email address.
  • Call check() function and pass the email address which you want to validate.
    • Returns TRUE, if the given email address is valid and real. Also, it indicates that the domain of this email exists and the user is valid.
    • Returns FALSE, if the given email address is invalid and not exists.
  • If the check() function returns FALSE, you can check the email with validate() function to check if the email format is valid but the user not exists on the domain.
<?php

// Include library file
require_once 'VerifyEmail.class.php'

// Initialize library class
$mail = new VerifyEmail();

// Set the timeout value on stream
$mail->setStreamTimeoutWait(20);

// Set debug output mode
$mail->DebugTRUE
$mail->Debugoutput'html'

// Set email address for SMTP request
$mail->setEmailFrom('from@email.com');

// Email to check
$email 'email@example.com'

// Check if email is valid and exist
if($mail->check($email)){ 
    echo 
'Email &lt;'.$email.'&gt; is exist!'
}elseif(
verifyEmail::validate($email)){ 
    echo 
'Email &lt;'.$email.'&gt; is valid, but not exist!'
}else{ 
    echo 
'Email &lt;'.$email.'&gt; is not valid and not exist!'


?>

Email validation in JavaScript using Regular Expression

Do you want to get implementation help, or enhance the functionality of this script? Click here to Submit Service Request

9 Comments

  1. Marty Said...
  2. Pugazh Yazhi G Said...
  3. Abo Baker Saddique Said...
  4. Knud Said...
  5. Jon Said...
  6. Christian Said...
  7. Htet Said...
  8. Waleed Aslam Said...
  9. Waleed Aslam Said...

Leave a reply

keyboard_double_arrow_up