Formas de validar un correo electrónico

·

Una de las cosas que habitualmente es necesario hacer es validar cuentas de correo. Hay muchas cosas a hacer, pero una de las primeras es saber si la cuenta de correo está «bien formada». Un artículo muy interesante sobre distintas formas de verificar cuentas, basadas en una serie de expresiones que sí han de validar, y otras que no han de hacerlo.

La expresión que en principio se ajusta más a todas las posibilidades es la siguiente:

/^([\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+\.)*[\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+@((((([a-z0-9]{1}[a-z0-9\-]{0,62}[a-z0-9]{1})|[a-z])\.)+[a-z]{2,6})|(\d{1,3}\.){3}\d{1,3}(\:\d{1,5})?)$/i

Con esto tendríamos un código similar a este:

<?php
$texto = "prueba@ejemplo.com";
$expresion = "/^([\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+\.)*[\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+@((((([a-z0-9]{1}[a-z0-9\-]{0,62}[a-z0-9]{1})|[a-z])\.)+[a-z]{2,6})|(\d{1,3}\.){3}\d{1,3}(\:\d{1,5})?)$/i";
preg_match($expresion , $texto , $encuentros);
print_r($encuentros);
?>

De todas formas, quizá habría que hacer otra cosa, que es verificar si realmente la cuenta existe… y es que una cosa es que la cuenta de correo esté bien formada y otra es que pueda hacer una prueba de envío de correo sin necesidad de enviar. Para eso podríamos usar una clase como esta que se conecta a la máquina remota para verificar la existencia de la cuenta…

<?php
class SMTP_validateEmail {
  var $sock;
  var $user;
  var $domain;
  var $domains;
  var $port = 25;
  var $max_conn_time = 30;
  var $max_read_time = 5;
  var $from_user = 'pruebas@ejemplo.com';
  var $from_domain = 'localhost';
  var $nameservers = array(
    '192.168.0.1'
  );
  var $debug = false;
  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);
  }
  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;
    }
  }
  function setSenderEmail($email) {
    $parts = $this->_parseEmail($email);
    $this->from_user = $parts[0];
    $this->from_domain = $parts[1];
  }
  function validate($emails = false, $sender = false) {
    $results = array();
    if ($emails) {
      $this->setEmails($emails);
    }
    if ($sender) {
      $this->setSenderEmail($sender);
    }
    foreach($this->domains as $domain=>$users) {
      $mxs = array();
      list($hosts, $mxweights) = $this->queryMX($domain);
      for($n=0; $n < count($hosts); $n++) {
        $mxs[$hosts[$n]] = $mxweights[$n];
      }
      asort($mxs);
      array_push($mxs, $this->domain);
      $this->debug(print_r($mxs, 1));
      $timeout = $this->max_conn_time/count($hosts);
      while(list($host) = each($mxs)) {
        $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;
        }
      }
      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') {
          foreach($users as $user) {
            $results[$user.'@'.$domain] = false;
          }
          continue;
        }
        $this->send("HELO ".$this->from_domain);
        $this->send("MAIL FROM: < ".$this->from_user.'@'.$this->from_domain.">");
        foreach($users as $user) {
          $reply = $this->send("RCPT TO: < ".$user.'@'.$domain.">");
          preg_match('/^([0-9]{3}) /ims', $reply, $matches);
          $code = isset($matches[1]) ? $matches[1] : '';
          if ($code == '250') {
            $results[$user.'@'.$domain] = true;
          } elseif ($code == '451' || $code == '452') {
            $results[$user.'@'.$domain] = true;
          } else {
            $results[$user.'@'.$domain] = false;
          }
        }
        $this->send("quit");
        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;
  }
  function queryMX($domain) {
    $hosts = array();
    $mxweights = array();
    if (function_exists('getmxrr')) {
      getmxrr($domain, $hosts, $mxweights);
    } else {
      require_once 'Net/DNS.php'; // http://pear.php.net/package/Net_DNS/
      $resolver = new Net_DNS_Resolver();
      $resolver->debug = $this->debug;
      $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);
  }
  function microtime_float() {
    list($usec, $sec) = explode(" ", microtime());
    return ((float)$usec + (float)$sec);
  }
  function debug($str) {
    if ($this->debug) {
      echo htmlentities($str);
    }
  }
}
?>

Comments

2 respuestas a «Formas de validar un correo electrónico»

  1. Avatar de Miguel

    Yo hasta la fecha comprobaba que la cuenta de correo estuviera bien validada, y además que el dominio exista, pero claro perfectamente con estas dos condiciones puede no existir de hay que requería el consabido envío de verificación, queda claro con este esquema puedo ahorrarme este tercer paso, lo tendré en cuenta para mis futuras implementaciones. Saludos!

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *