├── README ├── checkemailexample.php └── smtpvalidateclass.php /README: -------------------------------------------------------------------------------- 1 | How to check if an email address exists without sending an email? 2 | The PHP code demonstrates how the email server can be checked to see if an email address exists. This uses SMTP commands, if you are not familiar with them, please visit this page to see what commands are being used https://www.webdigi.co.uk/blog/2009/how-to-check-if-an-email-address-exists-without-sending-an-email/ 3 | 4 | Requirements (for this example): 5 | Any OS 6 | PHP 7 | 8 | Source: 9 | This is opensource and you are free to use it however you want. It comes with absolutely no warranty. 10 | 11 | Project Page: https://www.webdigi.co.uk/blog/2009/how-to-check-if-an-email-address-exists-without-sending-an-email/ 12 | 13 | Brought to you by Webdigi, a Web Development Company https://www.webdigi.co.uk/ 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /checkemailexample.php: -------------------------------------------------------------------------------- 1 | validate($emails, $sender); 13 | // view results 14 | var_dump($result); 15 | echo $email.' is '.($result ? 'valid' : 'invalid')."\n"; 16 | 17 | // send email? 18 | if ($result) { 19 | //mail(...); 20 | } 21 | 22 | ?> 23 | -------------------------------------------------------------------------------- /smtpvalidateclass.php: -------------------------------------------------------------------------------- 1 | setEmails($emails); 72 | } 73 | if ($sender) { 74 | $this->setSenderEmail($sender); 75 | } 76 | } 77 | 78 | function _parseEmail($email) { 79 | $parts = explode('@', $email); 80 | $domain = array_pop($parts); 81 | $user= implode('@', $parts); 82 | return array($user, $domain); 83 | } 84 | 85 | /** 86 | * Set the Emails to validate 87 | * @param $emails Array List of Emails 88 | */ 89 | function setEmails($emails) { 90 | foreach($emails as $email) { 91 | list($user, $domain) = $this->_parseEmail($email); 92 | if (!isset($this->domains[$domain])) { 93 | $this->domains[$domain] = array(); 94 | } 95 | $this->domains[$domain][] = $user; 96 | } 97 | } 98 | 99 | /** 100 | * Set the Email of the sender/validator 101 | * @param $email String 102 | */ 103 | function setSenderEmail($email) { 104 | $parts = $this->_parseEmail($email); 105 | $this->from_user = $parts[0]; 106 | $this->from_domain = $parts[1]; 107 | } 108 | 109 | /** 110 | * Validate Email Addresses 111 | * @param String $emails Emails to validate (recipient emails) 112 | * @param String $sender Sender's Email 113 | * @return Array Associative List of Emails and their validation results 114 | */ 115 | function validate($emails = false, $sender = false) { 116 | 117 | $results = array(); 118 | 119 | if ($emails) { 120 | $this->setEmails($emails); 121 | } 122 | if ($sender) { 123 | $this->setSenderEmail($sender); 124 | } 125 | 126 | // query the MTAs on each Domain 127 | foreach($this->domains as $domain=>$users) { 128 | 129 | $mxs = array(); 130 | 131 | // retrieve SMTP Server via MX query on domain 132 | list($hosts, $mxweights) = $this->queryMX($domain); 133 | 134 | // retrieve MX priorities 135 | for($n=0; $n < count($hosts); $n++){ 136 | $mxs[$hosts[$n]] = $mxweights[$n]; 137 | } 138 | asort($mxs); 139 | 140 | // last fallback is the original domain 141 | array_push($mxs, $this->domain); 142 | 143 | $this->debug(print_r($mxs, 1)); 144 | 145 | $timeout = $this->max_conn_time/(count($hosts)>0 ? count($hosts) : 1); 146 | 147 | // try each host 148 | while(list($host) = each($mxs)) { 149 | // connect to SMTP server 150 | $this->debug("try $host:$this->port\n"); 151 | if ($this->sock = fsockopen($host, $this->port, $errno, $errstr, (float) $timeout)) { 152 | stream_set_timeout($this->sock, $this->max_read_time); 153 | break; 154 | } 155 | } 156 | 157 | // did we get a TCP socket 158 | if ($this->sock) { 159 | $reply = fread($this->sock, 2082); 160 | $this->debug("<<<\n$reply"); 161 | 162 | preg_match('/^([0-9]{3})/ims', $reply, $matches); 163 | $code = isset($matches[1]) ? $matches[1] : ''; 164 | 165 | if($code != '220') { 166 | // MTA gave an error... 167 | foreach($users as $user) { 168 | $results[$user.'@'.$domain] = false; 169 | } 170 | continue; 171 | } 172 | 173 | // say helo 174 | $this->send("HELO ".$this->from_domain); 175 | // tell of sender 176 | $this->send("MAIL FROM: <".$this->from_user.'@'.$this->from_domain.">"); 177 | 178 | // ask for each recepient on this domain 179 | foreach($users as $user) { 180 | 181 | // ask of recepient 182 | $reply = $this->send("RCPT TO: <".$user.'@'.$domain.">"); 183 | 184 | // get code and msg from response 185 | preg_match('/^([0-9]{3}) /ims', $reply, $matches); 186 | $code = isset($matches[1]) ? $matches[1] : ''; 187 | 188 | if ($code == '250') { 189 | // you received 250 so the email address was accepted 190 | $results[$user.'@'.$domain] = true; 191 | } elseif ($code == '451' || $code == '452') { 192 | // you received 451 so the email address was greylisted (or some temporary error occured on the MTA) - so assume is ok 193 | $results[$user.'@'.$domain] = true; 194 | } else { 195 | $results[$user.'@'.$domain] = false; 196 | } 197 | 198 | } 199 | 200 | // quit 201 | $this->send("quit"); 202 | // close socket 203 | fclose($this->sock); 204 | 205 | } 206 | } 207 | return $results; 208 | } 209 | 210 | 211 | function send($msg) { 212 | fwrite($this->sock, $msg."\r\n"); 213 | 214 | $reply = fread($this->sock, 2082); 215 | 216 | $this->debug(">>>\n$msg\n"); 217 | $this->debug("<<<\n$reply"); 218 | 219 | return $reply; 220 | } 221 | 222 | /** 223 | * Query DNS server for MX entries 224 | * @return 225 | */ 226 | function queryMX($domain) { 227 | $hosts = array(); 228 | $mxweights = array(); 229 | if (function_exists('getmxrr')) { 230 | getmxrr($domain, $hosts, $mxweights); 231 | } else { 232 | // windows, we need Net_DNS 233 | require_once 'Net/DNS.php'; 234 | 235 | $resolver = new Net_DNS_Resolver(); 236 | $resolver->debug = $this->debug; 237 | // nameservers to query 238 | $resolver->nameservers = $this->nameservers; 239 | $resp = $resolver->query($domain, 'MX'); 240 | if ($resp) { 241 | foreach($resp->answer as $answer) { 242 | $hosts[] = $answer->exchange; 243 | $mxweights[] = $answer->preference; 244 | } 245 | } 246 | 247 | } 248 | return array($hosts, $mxweights); 249 | } 250 | 251 | /** 252 | * Simple function to replicate PHP 5 behaviour. http://php.net/microtime 253 | */ 254 | function microtime_float() { 255 | list($usec, $sec) = explode(" ", microtime()); 256 | return ((float)$usec + (float)$sec); 257 | } 258 | 259 | function debug($str) { 260 | if ($this->debug) { 261 | echo htmlentities($str); 262 | } 263 | } 264 | 265 | } 266 | 267 | 268 | ?> 269 | --------------------------------------------------------------------------------