对于普通的邮件地址,一般都只是做命名合法的有效性,但是对于邮件地址是否存在等无法做有效的验证。通过网上的资料查看以下方式可以进行较完整的验证,但是在测试过程中发现还是不够那么完善,但是此方式是我看到用代码层面去确定的最好方式了:
- <?php
- /**
- * Validate Email Addresses Via SMTP
- * This queries the SMTP server to see if the email address isaccepted.
- * @copyright -Please keep this comment intact
- * @author gabe@fijiwebdesign.com
- * @contributers adnan@barakatdesigns.net
- * @version 0.1a
- */
- 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);
- }
-
- /**
- * Set the Emails to validate
- * @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)) {
- // connect to SMTP server
- $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
- $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(">>>\n$msg\n");
- $this->debug("<<<\n$reply");
-
- return $reply;
- }
-
- /**
- * Query DNS server for MX entries
- * @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.
- */
- function microtime_float()
- {
- list($usec, $sec) = explode(" ", microtime());
- return ((float)$usec + (float)$sec);
- }
-
- function debug($str)
- {
- if ($this->debug) {
- echo '
'
.htmlentities($str).'';
- }
- }
- }
- ?>
- //调用例子
- <?php
- // include SMTP Email Validation Class
- require_once('testEmailVaild.php');
- // the email to validate
- $email = '163chenweicai@163.com';
- // an optional sender
- $sender = 'glb0@chinanetcenter.com';
- // 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
- $results = $SMTP_Validator->validate(array($email),$sender);
- // view results
- echo $email.' is '.($results[$email] ? 'valid' :'invalid')."\n";
- // send email?
- if ($results[$email]) {
- //mail($email, 'Confirm Email', 'Please reply to this email to confirm', 'From:'.$sender."\r\n"); // send email
- }
- else {
- echo 'The email addresses you entered is not valid';
- }
- ?>
以上代码来源于其它地方,由于是上次保持到本地的,已经找不到。若代码所属者看到此代码要求删除可以留言。
后来在多次的测试中发现,其实sendmail本身对于发送失败的地址会有相关的返回值,此信息可以从$mail->ErrorInfo函数中获取,在failed to load: recipients_字符串后面会有发送失败的地址。我们可以对发送的邮件地址进行多次发送,第一次发送就可以获取失败的地址,然后进行记录并通知,以后的发送读取发送的失败的地址进行过滤。从而可以解决这个问题。相比于上述第一种方法,会多一次发送的时间,但是在准确性方面却有很好的保证。
阅读(5670) | 评论(0) | 转发(0) |