Validate email with smtp

This function validate a mail address in a smart way: if the address to validate has a correct syntax (checked…

December 27, 2009

This function validate a mail address in a smart way: if the address to validate has a correct syntax (checked with regular expression), it tries to connect to the mx server of the address. This means that the program have to use the smtp protocol to talk with each mx server registered in the dns for that domain address.
When a connection with an mx server is established, the program presents himself with the $probe_address (if no probe_address is specified it will use the SERVER_ADMIN setting of the php.ini file) and asks to send a mail message to the address to validate. If the server responds that the destination mailbox is ok, it stops and return ok value, else it gives you the bad answer of the mail server.
Sometimes this process fails due to timeouts, or gives a bad answer because some mail servers are configured to respond always: “yes this destination mail exists!”… So… you should trust this code not at 100%.
The best way to check if a mail address really exists is double opt in. But this function is cool, suppose to use it in an ajax form. :-)
Here is a working demo of Smtp Mail Validation function.

This code is included into the Mini Bots Php Class.

function validateEmailSmtp($email, $probe_address="", $debug=false) {
	# --------------------------------
	# function to validate email address
	# through a smtp connection with the
	# mail server.
	# by Giulio Pons
	# http://www.barattalo.it
	# --------------------------------
	$output = "";
	# --------------------------------
	# Check syntax with regular expression
	# --------------------------------
	if (!$probe_address) $probe_address = $_SERVER["SERVER_ADMIN"];
	if (preg_match('/^([a-zA-Z0-9\._\+-]+)\@((\[?)[a-zA-Z0-9\-\.]+\.([a-zA-Z]{2,7}|[0-9]{1,3})(\]?))$/', $email, $matches)) {
		$user = $matches[1];
		$domain = $matches[2];
		# --------------------------------
		# Check availability of DNS MX records
		# --------------------------------
		if (function_exists('checkdnsrr')) {
			# --------------------------------
			# Construct array of available mailservers
			# --------------------------------
			if(getmxrr($domain, $mxhosts, $mxweight)) {
				for($i=0;$i<count($mxhosts);$i++){
					$mxs[$mxhosts[$i]] = $mxweight[$i];
				}
				asort($mxs);
				$mailers = array_keys($mxs);
			} elseif(checkdnsrr($domain, 'A')) {
				$mailers[0] = gethostbyname($domain);
			} else {
				$mailers=array();
			}
			$total = count($mailers);
			# --------------------------------
			# Query each mailserver
			# --------------------------------
			if($total > 0) {
				# --------------------------------
				# Check if mailers accept mail
				# --------------------------------
				for($n=0; $n < $total; $n++) {
					# --------------------------------
					# Check if socket can be opened
					# --------------------------------
					if($debug) { $output .= "Checking server $mailers[$n]...\n";}
					$connect_timeout = 2;
					$errno = 0;
					$errstr = 0;
					# --------------------------------
					# controllo probe address
					# --------------------------------
					if (preg_match('/^([a-zA-Z0-9\._\+-]+)\@((\[?)[a-zA-Z0-9\-\.]+\.([a-zA-Z]{2,7}|[0-9]{1,3})(\]?))$/', $probe_address,$fakematches)) {
						$probe_domain = str_replace("@","",strstr($probe_address, '@'));

						# --------------------------------
						# Try to open up socket
						# --------------------------------
						if($sock = @fsockopen($mailers[$n], 25, $errno , $errstr, $connect_timeout)) {
							$response = fgets($sock);
							if($debug) {$output .= "Opening up socket to $mailers[$n]... Success!\n";}
							stream_set_timeout($sock, 5);
							$meta = stream_get_meta_data($sock);
							if($debug) { $output .= "$mailers[$n] replied: $response\n";}
							# --------------------------------
							# Be sure to set this correctly!
							# --------------------------------
							$cmds = array(
								"HELO $probe_domain",
								"MAIL FROM: <$probe_address>",
								"RCPT TO: <$email>",
								"QUIT",
							);
							# --------------------------------
							# Hard error on connect -> break out
							# --------------------------------
							if(!$meta['timed_out'] && !preg_match('/^2\d\d[ -]/', $response)) {
								$codice = trim(substr(trim($response),0,3));
								if ($codice=="421") {
									//421 #4.4.5 Too many connections to this host.
									$error = $response;
									break;
								} else {
									if($response=="" || $codice=="") {
										//c'è stato un errore ma la situazione è poco chiara
										$codice = "0";
									}
									$error = "Error: $mailers[$n] said: $response\n";
									break;
								}
								break;
							}
							foreach($cmds as $cmd) {
								$before = microtime(true);
								fputs($sock, "$cmd\r\n");
								$response = fgets($sock, 4096);
								$t = 1000*(microtime(true)-$before);
								if($debug) {$output .= "$cmd\n$response" . "(" . sprintf('%.2f', $t) . " ms)\n";}
								if(!$meta['timed_out'] && preg_match('/^5\d\d[ -]/', $response)) {
									$codice = trim(substr(trim($response),0,3));
									if ($codice<>"552") {
										$error = "Unverified address: $mailers[$n] said: $response";
										break 2;
									} else {
										$error = $response;
										break 2;
									}
									# --------------------------------
									// il 554 e il 552 sono quota
									// 554 Recipient address rejected: mailbox overquota
									// 552 RCPT TO: Mailbox disk quota exceeded
									# --------------------------------
								}
							}
							fclose($sock);
							if($debug) { $output .= "Succesful communication with $mailers[$n], no hard errors, assuming OK\n";}
							break;
						} elseif($n == $total-1) {
							$error = "None of the mailservers listed for $domain could be contacted";
							$codice = "0";
						}
					} else {
						$error = "Il probe_address non è una mail valida.";
					}
				}
			} elseif($total <= 0) {
				$error = "No usable DNS records found for domain '$domain'";
			}
		}
	} else {
		$error = 'Address syntax not correct';
	}
	if($debug) {
		print nl2br(htmlentities($output));
	}
	if(!isset($codice)) {$codice="n.a.";}
	if(isset($error)) return array($error,$codice); else return true;
}

Author

I'm a software engineer, an everyday web developer and a maker. I usually build sites with PHP, within or without WordPress. I build Internet of Things with Arduino and ESP8266. I'm the founder of Rockit.it and Dailybest.it and I'm actually the Chief Technical Officer of Better Days web agency.

Comments on “Validate email with smtp”

10 thoughts

  1. sam says:

    this is awesome

  2. Good Forex says:

    cool, great information you write it very clean. I am very lucky to get this tips from you. ;-)

  3. Dario says:

    Ciao, bellissimo script!!!
    ma come devo fare per far partire la funzione?

  4. Billy B says:

    An issue we have on one of sites is with users registering with fake emails. And even though we do email activation this results in a lot of bounced emails in my inbox. Could i check the emails through this function during registration or would it take too long?

  5. Pawel says:

    Why when I ask about gmail email I get ony this:
    Checking server gmail-smtp-in.l.google.com…
    Checking server alt1.gmail-smtp-in.l.google.com…
    Checking server alt2.gmail-smtp-in.l.google.com…
    Checking server alt3.gmail-smtp-in.l.google.com…
    Checking server alt4.gmail-smtp-in.l.google.com..

    nothing else. On your demo page it works ok.

  6. Joe says:

    I am trying to use your script but do not know how to activate.

    Could you please give me a sample useage, how to get it working

    Grazie

  7. Joe says:

    I have downloaded your mini bots php class and index.

    Could you please explain how to use this

    Thanks

  8. Joe says:

    Hi

    I am trying to incorporate your Smtp Mail Validation function into my website but am having a little difficulty.

    Could you please give me some instructions on how to incorporate your script

    Thanks

  9. Giulio Pons says:

    it’s just a function, use it after the user insert the email in your website.

  10. Dav says:

    i notice the demo works with gmail etc. has the code changed?

Comments are closed

Recommended

Modify the language attribute based on category in WordPress

How to modify the language attribute in your Wordpress theme using a specific value

November 7, 2019

Count coloured cells on Google Sheets with reference

In a spreadsheet if you need to count cells based on their background you can use this code in Google…

May 22, 2020

WP doesn’t send email? try this

Snippets for sending emails with Wordpress

February 8, 2020

Two post types share the same taxonomy in WordPress

Sharing a WordPress taxonomy between two post types is useful especially if you want to create a relation between different…

November 14, 2019

MYSQL add counter in a query

Use mysql variables to create a counter in SQL, PHP code to use an SQL counter and what does the i mean in mysqli?

November 9, 2019

WordPress Fatal error: Unknown: Cannot use output buffering in output buffering display handlers in Unknown on line 0

How I've beat the php mysterious fatal error unknown in Wordpress caused by caching plugin WP Fastest Cache

November 7, 2019