通过 SMTP 来检测邮箱的有效性

如何来检测一个 email 地址?一般就需要从邮件地址的 smtp 服务器来获取一些信息来判断。

假设我要检测 testmail@douban.com 这个地址是不是真存在:

首先需要取得 douban.com 这个域的 MX 记录:
dig douban.com MX

然后根据得到的 MX 地址来检测,用 telnet MX记录 端口号 来连接,然后输入命令:
verify

从结果中基本可以看到 testmail@douban.com 这个地址返回的是 250 状态,是存在的;而下面的 jfksdjglfdgld@douban.com 则返回了 550 状态,同时也可以从下面的描述语句中得到这个地址则是不存在的。

下在的类就是根据上面的脚本写的一个 php 类,用来检测邮件地址是否真实存在。

<?php
/**
* 检测一个邮件地址是否真实存在
*/
class verify_email {
public $debug = FALSE;
public $time_out = 30;
public $host_name = 'localhost';
public $smtp_port = 25;
public $log_str = "";
public $from = '';
public $sock;
public function __construct($from = "", $smtp_port = 25) {
$this->smtp_port = $smtp_port;
$this->from = $from;
$this->time_out = 30; //is used in fsockopen()
$this->sock = FALSE;
}
public function check_mail($address) {
$this->log_write("BEGINING CHECK address: ". $address . "\n");
if(!$this->is_email($address)) {
$this->log_write("not an email address.\n");
return FALSE;
}
//
if (TRUE !== $this->smtp_sockopen($address)) {
return FALSE;
}
if (!$this->smtp_putcmd("HELO", $this->host_name)) {
$this->log_write("sending HELO command\n");
return FALSE;
}
if (!$this->smtp_putcmd("MAIL", "FROM:<" . $this->from . ">")) {
$this->log_write("sending MAIL FROM command\n");
return FALSE;
}
if (!$this->smtp_putcmd("RCPT", "TO:<" . $address . ">")) {
$this->log_write("sending MAIL TO command\n");
return FALSE;
}
return TRUE;
}
private function is_email($address) {
return preg_match("/^[0-9a-zA-Z]+@(([0-9a-zA-Z]+)[.])+[a-z]{2,4}$/i",$address);
}
private function smtp_sockopen($address) {
return $this->smtp_sockopen_mx($address);
}
private function smtp_sockopen_mx($address) {
$domain = preg_replace("/^.+@([^@]+)$/i", "$1", $address);
if (!@getmxrr($domain, $MXHOSTS)) {
$this->log_write("Error: Cannot resolve MX \"" . $domain . "\"\n");
return FALSE;
}
foreach ($MXHOSTS as $host) {
$this->log_write("Trying to " . $host . ":" . $this->smtp_port . "\n");
$this->sock = @fsockopen($host, $this->smtp_port, $errno, $errstr, $this->time_out);
if (!($this->sock && $this->smtp_ok())) {
$this->log_write("Warning: Cannot connect to mx host " . $host . "\n");
$this->log_write("Error: " . $errstr . " (" . $errno . ")\n");
continue;
}
$this->log_write("Connected to mx host " . $host . "\n");
return TRUE;
}
$this->log_write("Error: Cannot connect to any mx hosts (" . implode(", ", $MXHOSTS) . ")\n");
return FALSE;
}
private function smtp_putcmd($cmd, $arg = "") {
if ($arg != "") {
if ($cmd == "")
$cmd = $arg;
else
$cmd = $cmd . " " . $arg;
}
fputs($this->sock, $cmd . "\r\n");
$this->smtp_debug("> " . $cmd . "\n");
return $this->smtp_ok();
}
private function smtp_ok() {
$response = str_replace("\r\n", "", fgets($this->sock, 512));
$this->smtp_debug($response . "\n\n");
if (!ereg("^[23]", $response)) {
fputs($this->sock, "QUIT\r\n");
fgets($this->sock, 512);
$this->log_write("Error: Remote host returned \"" . $response . "\"\n");
return FALSE;
}
return TRUE;
}
private function log_write($str) {
$this->log_str .= $str;
}
public function get_log() {
$str = $this->log_str;
$this->log_str = '';
return $str;
}
private function smtp_debug($message) {
if ($this->debug) {
echo $message;
}
}
}
// Testing
$newemail = "doubanjgdl@kfdkldfg@163.com";
$randval = substr(md5(uniqid(rand())), 0, 6);
$verifyEmail = new verify_email($randval . "@mailtest.com");
echo $newemail . ' is ';
if (TRUE === $verifyEmail->check_mail($newemail)) {
echo "OK\n";
} else {
echo "BAD\n";
}
//echo $verifyEmail->get_log();