SMTP和STMP命令 具体SMTP指令问题不做深究 有兴趣者可参考http://www.magicwinmail.com/technic_smtp.php Smtp(Simple Mail Transfer Protocol)协议是为保证电子邮件的可靠和高效传输,TCP/IP协议的应用层中包含有SMTP协议,但是事实上其与传输系统和机制无关,只要一个 可靠的数据流通道,该协议可以工作在TCP上,也可以工作在NCP,NITS等协议上,在TCP上,其使用端口25进行传输。STMP的重要特点是可以交 互的通信系统中传发邮件。 SMTP提供了一种邮件传输的机制,当接受方和发送方都种子 一 个网络上时,可以把邮件直接传给对方,当双方不在同一网络上时,需要通过一个或几个中间服务器转发。STMP首先由发送方提供声请,要求与控接方SMTP 建立双向通道,接收方可以是最后接件人也可以是中间转发的服务器,接收服务器确认可以建立连接后,双发就可以开始通信。 发送方SMTP向接受方发出Mail命令,告知发送方的身份,如果回答OK。发送方再发出RCPT命令,告知收件人的身份,接收方SMTP确认是否接收或转发,如果同意就回答OK,接下来几可以进程数据传输拉。 那SMTP 的命令是什么拉?STMP中定义15个命令,其中SMTP工作的基本的命令有7个,HELO,MAILFROM,RCPT TO,DATA,REST,NOOP和QUIT; 下面我们介绍一下这几个命令: HELO:发送方问候接收方,后面是发件人的服务器地址或标志; MAILFROM:开始发送邮件,起后面跟随发送邮件发送方 的地址; RCPT TO:接受方收件人的邮箱 DATA:接收方把把该命令之后的数据作为发送数据; REST:接收方复位; NOOP:这个命令不影响任何参数,只是要求接收回答OK,不会影响缓冲区的数据; OUIT;SMTP要求接受方需要回答OK;然后中断传输在接到这个命令并回答OK前,接受方不得中断连接,即使传输出现错误。 <?php /** * Validate Email Addresses Via SMTP * This queries the SMTP server to see if the email address isaccepted. * @author [email protected] * @version 0.1a */ header("Content-type: text/html; charset=utf-8"); class SMTP_validateEmail { /** * PHP Socket resource to remote MTA * @var resource $sock */ var $sock; /** * Current User being validated */ var $user; /** * Current domain where user is being validated */ var $domain; /** * List of domains to validate users on */ var $domains; /** * SMTP Port */ var $port = 25; /** * Maximum Connection Time to wait for connectionestablishment per MTA */ var $max_conn_time = 30; /** * Maximum time to read from socket before giving up */ var $max_read_time = 5; /** * username of sender */ var $from_user = 'user'; /** * Host Name of sender */ var $from_domain = 'localhost'; /** * Nameservers to use when make DNS query for MX entries * @var Array $nameservers */ var $nameservers = array( '192.168.0.1' ); var $debug = false; /** * Initializes the Class * @return SMTP_validateEmail Instance * @param $email Array[optional] List of Emails toValidate * @param $sender String[optional] Email of validator */ function SMTP_validateEmail($emails = false, $sender =false) { if ($emails) { $this->setEmails($emails); } if ($sender) { $this->setSenderEmail($sender); } } //解析邮箱地址 function _parseEmail($email) { $parts = explode('@', $email); $domain = array_pop($parts); $user= implode('@', $parts); return array($user, $domain); } /** * 设置受事邮件地址 * @param $emails Array List of Emails */ function setEmails($emails) { foreach ($emails as $email) { list($user, $domain) = $this->_parseEmail($email); if (!isset($this->domains[$domain])) { $this->domains[$domain] = array(); } $this->domains[$domain][] = $user; } } /** * Set the Email of the sender/validator * @param $email String */ function setSenderEmail($email) { $parts = $this->_parseEmail($email); $this->from_user = $parts[0];//邮箱地址 $this->from_domain = $parts[1];//邮箱域名 } /** * Validate Email Addresses * @param String $emails Emails to validate (recipientemails) * @param String $sender Sender's Email * @return Array Associative List of Emails and theirvalidation results */ function validate($emails = false, $sender = false) { $results = array(); if ($emails) { //设置受事邮件地址 $this->setEmails($emails); } if ($sender) { //设置发信人 $this->setSenderEmail($sender); } // query the MTAs on each Domain foreach($this->domains as $domain=>$users) { $mxs = array(); // current domain being queried $this->domain = $domain; // retrieve SMTP Server via MX query on domain list($hosts, $mxweights) = $this->queryMX($domain); // retrieve MX priorities for($n = 0; $n < count($hosts); $n++){ $mxs[$hosts[$n]] = $mxweights[$n]; } asort($mxs); // last fallback is the original domain $mxs[$this->domain] = 0; $this->debug(print_r($mxs, 1)); $timeout = $this->max_conn_time; // try each host while(list($host) = each($mxs)) { // 用fsockopen链接受事地址STMP服务器 $this->debug("try $host:$this->port\n"); if ($this->sock = fsockopen($host, $this->port, $errno, $errstr, (float) $timeout)) { stream_set_timeout($this->sock, $this->max_read_time); break; } } //did we get a TCP socket if ($this->sock) { $reply = fread($this->sock, 2082); $this->debug("<<<\n$reply"); preg_match('/^([0-9]{3}) /ims', $reply,$matches); $code = isset($matches[1]) ? $matches[1] : ''; if($code != '220') { // MTA gave an error... foreach($users as $user) { $results[$user.'@'.$domain] = false; } continue; } // say helo $this->send("HELO ".$this->from_domain); // tell of sender $this->send("MAIL FROM: <".$this->from_user.'@'.$this->from_domain.">"); // ask for each recepient on this domain foreach($users as $user) { // ask of recepient 请求受事邮件地址 $reply = $this->send("RCPT TO: <".$user.'@'.$domain.">"); // get code and msg from response 获得返回码 preg_match('/^([0-9]{3}) /ims', $reply,$matches); $code = isset($matches[1]) ? $matches[1] : ''; if ($code == '250') { // you received 250 so the email address was accepted 250表示已收信 $results[$user.'@'.$domain] =true; } elseif ($code == '451' || $code == '452') { // you received 451 so the email address was greylisted (or some temporary error occured on the MTA) - so assume is ok $results[$user.'@'.$domain] =true; } else { $results[$user.'@'.$domain] =false; } } // reset before quit $this->send("RSET"); // quit $this->send("quit"); // close socket fclose($this->sock); } } return $results; } //向受事服务器发送指令 function send($msg) { fwrite($this->sock, $msg."\r\n"); $reply = fread($this->sock, 2082); $this->debug("END\n$msg\n"); $this->debug("START\n$reply"); return $reply; } /** * Query DNS server for MX entries getmxrr()函数取得指定网址 DNS 记录之 MX 字段。 * @return */ function queryMX($domain) { $hosts = array(); $mxweights = array(); if (function_exists('getmxrr')) { getmxrr($domain, $hosts, $mxweights); } else { // windows, we need Net_DNS require_once 'Net/DNS.php'; $resolver = new Net_DNS_Resolver(); $resolver->debug = $this->debug; // nameservers to query $resolver->nameservers = $this->nameservers; $resp = $resolver->query($domain, 'MX'); if ($resp) { foreach($resp->answer as $answer) { $hosts[] = $answer->exchange; $mxweights[] = $answer->preference; } } } return array($hosts, $mxweights); } /** * Simple function to replicate PHP 5 behaviour.http://php.net/microtime */ function microtime_float() { list($usec, $sec) = explode(" ", microtime()); return ((float)$usec + (float)$sec); } function debug($str) { if ($this->debug) { echo '<pre>'.htmlentities($str).'</pre>'; } } } set_time_limit(0); //清空并关闭输出缓存 ob_end_clean(); flush(); //将输出发送给客户端浏览器 $mail_list = "add.txt"; $fp = fopen($mail_list,'r'); while(!feof($fp)){ $list[] = trim(fgets($fp)); } //$email = '[email protected]'; // an optional sender $sender = '[email protected]'; // instantiate the class $SMTP_Validator = new SMTP_validateEmail(); // turn on debugging if you want to view the SMTP transaction $SMTP_Validator->debug = true; // do the validation foreach($list as $k=>$who){ if($who != ''){ $results = $SMTP_Validator->validate(array($who),$sender); // view results //echo 'ok'; echo $who.' 是'.($results[$who] ? '有效的' :'无效的')."\n"; if($results[$who]){ file_put_contents('result.txt',$who. "\r\n", FILE_APPEND); } // send email? if ($results[$who]) { //mail($email, 'Confirm Email', 'Please reply to this email to confirm', 'From:'.$sender."\r\n"); // send email } else { //file_put_contents('result.txt',$who. "\r\n", FILE_APPEND); //echo 'The email addresses you entered is not valid'; } } }
本文出自 “长长技术博客” 博客,谢绝转载!