PHP: Verificar la existencia de una dirección de correo
07 de Mayo de 2007 en Programación, PHP
Lecturas: 28,832

MailAlgunas veces se necesita validar una cuenta de correo introducida por un usuario. Las formas más conocidas pasan por chequear la validez de la construcción de la dirección de correo mediante regular expresions y enviarle un mensaje de validación a esa cuenta y que el usuario le dé a algun link.

Pero yo buscaba algún sistema que me dijera si una dirección de correo existe realmente sin enviarle un mail de validación, y he encontrado un método que consulta a un servidor DNS por la existencia del dominio y luego le pregunta al servidor del dominio por la existencia del mailbox.

Después de mucho buscar encuentro en Tienhuis Networking un sistema que realiza tres pasos para comprobar una dirección de correo:

  1. Comprueba la correcta construcción mediante una expresión regular.
  2. Comprueba la existencia y disponibilidad de un registro MX en el DNS con el nombre del dominio de la dirección de mail.
  3. Comprueba si el mailserver encontrado accepta esa cuenta de mail.

La ventaja de este sistema de validación de correo es que no sólo se comprueba que la dirección contenga carácteres válidos, una arroba y una extensión de dominio válida, sino que consulta el propio servidor por su existencia.

Para realizar la segunda función se tira de la funcion de PHP getmxrr() (no disponible en servidores Windows!) que devuelve una posible lista de servidores de correo disponibles. Con éso podríamos decir que el dominio existe y que el servidor está en línea.

Pero para estar seguros que la cuenta existe y está operativa debemos probar la cuenta de correo contra los servidores encontrados en el punto anterior. Se abre un socket en el puerto 25 contra el servidor de correo y se le envía un conjunto de instrucciones directas (HELO, MAIL FROM, RCPT TO y QUIT) que servirán para provocar el error si la cuenta no existe en el servidor.

Este último punto es un poco engañoso, pues mientras el servidor de Hotmail (prueba por excelencia ;) ) funciona perfectamente, lo he probado en mi propio servidor de correo de mi hosting y responde OK para todas las cuentas que verifiquemos en su dominio, aunque no existan. Supongo que debe ser por tener activado el CatchAll, pero claro, ésto provoca falsos positivos. Si alguien tiene una idea será bienvenida ;)

Para poder probar y demostrar el sistema he colgado una página de test aquí: Check Mail. El código fuente de la función lo posteo a continuación, y lo pongo disponible para bajar aquí.

PHP:
  1. function validateEmail($email, $domainCheck = false, $verify = false, $return_errors=false) {
  2.     global $debug;
  3.     if($debug) {echo "<pre>";}
  4.     $errors = array();
  5.     # Check syntax with regex
  6.     if (preg_match('/^([a-zA-Z0-9\._\+-]+)\@((\[?)[a-zA-Z0-9\-\.]+\.([a-zA-Z]{2,7}|[0-9]{1,3})(\]?))$/', $email, $matches)) {
  7.         $user = $matches[1];
  8.         $domain = $matches[2];
  9.         # Check availability of DNS MX records
  10.         if ($domainCheck && function_exists('checkdnsrr')) {
  11.             # Construct array of available mailservers
  12.             if(getmxrr($domain, $mxhosts, $mxweight)) {
  13.                 for($i=0;$i<count($mxhosts);$i++){
  14.                     $mxs[$mxhosts[$i]] = $mxweight[$i];
  15.                 }
  16.                 asort($mxs);
  17.                 $mailers = array_keys($mxs);
  18.             } elseif(checkdnsrr($domain, 'A')) {
  19.                 $mailers[0] = gethostbyname($domain);
  20.             } else {
  21.                 $mailers=array();
  22.             }
  23.             $total = count($mailers);
  24.             # Query each mailserver
  25.             if($total> 0 && $verify) {
  26.                 # Check if mailers accept mail
  27.                 for($n=0; $n <$total; $n++) {
  28.                     # Check if socket can be opened
  29.                     if($debug) { echo "Checking server $mailers[$n]...\n";}
  30.                     $connect_timeout = 2;
  31.                     $errno = 0;
  32.                     $errstr = 0;
  33.                     $probe_address = 'postmaster@tienhuis.nl';
  34.                     # Try to open up socket
  35.                     if($sock = @fsockopen($mailers[$n], 25, $errno , $errstr, $connect_timeout)) {
  36.                         $response = fgets($sock);
  37.                         if($debug) {echo "Opening up socket to $mailers[$n]... Succes!\n";}
  38.                         stream_set_timeout($sock, 5);
  39.                         $meta = stream_get_meta_data($sock);
  40.                         if($debug) { echo "$mailers[$n] replied: $response\n";}
  41.                         $cmds = array(
  42.                             "HELO outkast.tienhuis.nl"# Be sure to set this correctly!
  43.                             "MAIL FROM: <$probe_address>",
  44.                             "RCPT TO: <$email>",
  45.                             "QUIT",
  46.                         );
  47.                         # Hard error on connect -> break out
  48.                         if(!$meta['timed_out'] && !preg_match('/^2\d\d[ -]/', $response)) {
  49.                             $error = "Error: $mailers[$n] said: $response\n";
  50.                             break;
  51.                         }
  52.                         foreach($cmds as $cmd) {
  53.                             $before = microtime(true);
  54.                             fputs($sock, "$cmd\r\n");
  55.                             $response = fgets($sock, 4096);
  56.                             $t = 1000*(microtime(true)-$before);
  57.                             if($debug) {echo htmlentities("$cmd\n$response") . "(" . sprintf('%.2f', $t) . " ms)\n";}
  58.                             if(!$meta['timed_out'] && preg_match('/^5\d\d[ -]/', $response)) {
  59.                                 $error = "Unverified address: $mailers[$n] said: $response";
  60.                                 break 2;
  61.                             }
  62.                         }
  63.                         fclose($sock);
  64.                         if($debug) { echo "Succesful communication with $mailers[$n], no hard errors, assuming OK";}
  65.                         break;
  66.                     } elseif($n == $total-1) {
  67.                         $errors = "None of the mailservers listed for $domain could be contacted";
  68.                     }
  69.                 }
  70.             } else {
  71.                 $error = "No usable DNS records found for domain '$domain'";
  72.             }
  73.         }
  74.     } else {
  75.         $error = 'Address syntax not correct';
  76.     }
  77.     if($debug) { echo "</pre>";}
  78.     #echo "</pre>";
  79.     if($return_errors) {
  80.         # Give back details about the error(s).
  81.         # Return FALSE if there are no errors.
  82.         # Keep this in mind when using it like:
  83.         # if(checkEmail($addr)) {
  84.         # Because of this strange behaviour this
  85.         # is not default ;-)
  86.         if(isset($error)) return htmlentities($error); else return false;
  87.     } else {
  88.         # 'Old' behaviour, simple to understand
  89.         if(isset($error)) return false; else return true;
  90.     }
  91. }

Tag:
 Enviar a Fresqui

Leer los Comentarios

[ # 927 ] Comment desde Zerjillo [08 de Mayo de 2007, 10:45]

Esta bien, pero normalmente hay que asegurarte de que la dirección introducida pertenece al usuario que la mete. Si no, se pueden hacer inscripciones de cuentas de otra gente, cosa que normalmente no es deseable.

[ # 928 ] Comment desde Xavi [08 de Mayo de 2007, 11:45]

Hay que verificar que la cuenta pertenece al usuario que la introduce, es cierto, pero lo que motivó ésto fué saber si una dirección realmente existía sin tener que enviarle un correo al usuario.

[ # 936 ] Comment desde Yo [08 de Mayo de 2007, 09:02]

Estupendo, los spammers ya no tienen que recoger información de la web, solo tienen que realizar combinaciones de letras y comprobar que existe el correo… cada vez lo tienen mas facil.

[ # 938 ] Comment desde Xavi [08 de Mayo de 2007, 10:53]

Vaya tela… sólo véis la parte mala del tema…

[ # 943 ] Comment desde Manuel Gonzalez [09 de Mayo de 2007, 09:51]

Muchas gracias por este código, Xavi.
De hecho, creo que es muy útil para verificar formularios como los que usan los clientes de mi empresa, ya que en ocasiones la gente escribe mal sus propios emails y se sorprenden al no recibir contestación en su buzón. Quizá los más geeks nunca cometemos esos fallos, pero la gente en general sí, os lo puedo asegurar.
Supongo que en hotmail cualquier combinación de letras dará casi siempre positivo, pero en general, la gente profesional cuenta con sus propios dominios, o de su empresa o colegio profesional, por lo que no habrá tantos falsos positivos.
Lo que sí que creo que hay que certificar es que nunca pueda provocar un falso negativo (”Su email es incorrecto, corríjalo”).
Gracias nuevamente.

[ # 945 ] Comment desde Xavi [09 de Mayo de 2007, 10:45]

De hecho, con Hotmail funciona perfectamente, pues responden KO para los mailbox no existentes.

He descubierto que si en vez del RCPT TO usamos VRFY en Hotmail no funciona pero en otros que fallaba antes va bién. Lo he estado consultando y parece que todo depende de la configuración del servidor de correo. Así que lo mejor sería pulirlo un poco.

De todas maneras, encuentro el sistema bastante útil.

Gracias Manuel ;)

[ # 948 ] Comment desde Chema [09 de Mayo de 2007, 01:59]

Hola, cuidado a los que lo usen, que le he encontrado un fallo de seguridad.

Si escribes

en el imput.

Saludos
Chema!

[ # 949 ] Comment desde Xavi [09 de Mayo de 2007, 02:45]

Chema, no ha salido lo que lo hace petar. Puedes volver a intentarlo? Gracias.

[ # 958 ] Pingback desde La Dragonera » L’atac dels referers extranys! :: Informatica, Motos, Lletres de Cançons [10 de Mayo de 2007, 09:45]

[…] www.edigital.com (verificar mail) […]

[ # 1076 ] Comment desde hernando [17 de Mayo de 2007, 09:29]

He mi9rado la pagina de prueba y en todos los email me pone ok. asi sean inventados.

[ # 1083 ] Comment desde andres [18 de Mayo de 2007, 04:12]

ya lo descrubri en mi servidor no esta disponible la funcion
checkdnsrr

[ # 1086 ] Comment desde Xavi [18 de Mayo de 2007, 08:06]

Es que a posteriori he descubierto que depende mucho de la implementación del servidor de correo. En algunos ciertas órdenes no funcionan, otras sí, y en otros al revés.

Mírate el comentario #945, te puede servir de ayuda.

El checkdnsrr no funciona? Algun error?

[ # 1561 ] Comment desde juan manu [10 de Junio de 2007, 09:10]

haber si llega que me tiene hasta el gorro.

[ # 1690 ] Comment desde Xavi [15 de Junio de 2007, 07:39]

Qué es lo que debe llegar?

[ # 2106 ] Comment desde Manuel [27 de Junio de 2007, 03:46]

Como puedo suscribirme a esta pagina no encuentro el enlace

[ # 2122 ] Comment desde Xavi [28 de Junio de 2007, 07:38]

Esta página no cuenta con suscripciones por correo, si te refieres a éso. Puedes sindicalizar el RSS de la página en tu lector de Feeds favorito usando el icono de la izquierda.

Saludos.

[ # 2154 ] Pingback desde PHP: Verificar la existencia de una dirección de correo - Noticias externas [30 de Junio de 2007, 12:53]

[…] Algunas veces se necesita validar una cuenta de correo introducida por un usuario. Las formas más conocidas pasan por chequear la validez de la construcción de la dirección de correo mediante regular expresions y enviarle un mensaje de validación a esa cuenta y que el usuario le dé a algun link. Pero yo buscaba algún sistema que me dijera si una dirección de correo existe realmente sin enviarle un mail de validación, y he encontrado un método que consulta a un servidor DNS por la existencia del dominio.» noticia original […]

[ # 2155 ] Pingback desde Verificar la existencia de una dirección de correo en PHP - Noticias externas [30 de Junio de 2007, 12:55]

[…] C&P "Algunas veces se necesita validar una cuenta de correo introducida por un usuario. Las formas más conocidas pasan por chequear la validez de la construcción de la dirección de correo mediante regular expresions y enviarle un mensaje de validación. Pero yo buscaba algún sistema que me dijera si una dirección de correo existe realmente sin enviarle un mail de validación, y he encontrado un método que consulta a un servidor DNS por la existencia del dominio y luego le pregunta al servidor del dominio por la existencia del mailbox."» noticia original […]

[ # 2160 ] Pingback desde Juanle.Info » Sistema para validar correo [30 de Junio de 2007, 09:04]

[…] Sin mas, les dejo el enlace oficial, donde el autor explica mejor como funciona, y deja el codigo fuente, click aqui […]

[ # 3307 ] Comment desde rufus [03 de Agosto de 2007, 05:49]

Nota: Esta función no debe ser usada para propósitos de verificación de direcciones. Solo los puntos de intercambio de correo en DNS son devueltos, sin embargo, de acuerdo a RFC 2821, cuando no se listan puntos de intercambio de correo, nombre_host mismo debería ser usado como el único punto de intercambio de correo con una prioridad de 0.

[ # 3361 ] Comment desde Xavi [06 de Agosto de 2007, 08:00]

Y porqué no debe ser usada para éso? Produce algún problema en los puntos de intercambio? Puedes echarnos algo de luz en el tema?

[ # 4254 ] Comment desde frandy [28 de Agosto de 2007, 05:11]

pues, creo que es un buen intento de hacer algo bueno, y me gusto que lo intentaran. pero lamentablemente no es funcional. dice KO a todo los emails inventados que uno escriba en el campo de texto.

[ # 4255 ] Comment desde frandy [28 de Agosto de 2007, 05:16]

jjajajajaja, lo siento.
El script si funciona, jejeje, pero rayos, quien se iba a dar cuenta de la forma en que funciona. cuando no existe retorna KO , mientras que cuando existe retorna OK.

[ # 4261 ] Comment desde Xavi [28 de Agosto de 2007, 07:10]

Le pregunta al DNS del servidor de correo destino si la cuenta existe y si existe retorna OK. Tiene alguna falla pues a veces devuelve falsos positivos a causa de lña gran cantidad de configuraciones y opciones de cada servidor en particular, pero puede dar una idea de si la cuenta esta falseada o no.
Saludos.

[ # 6064 ] Comment desde samuel [29 de Septiembre de 2007, 03:53]

A ver si aprender a ver las cosas como son, el script es muy bueno y es una base para quien requiera depurarlo, deberian de ser agradecidos bola de ignorantes. Si no les gusta como está hecho, ponganse a programar.

[ # 9458 ] Comment desde fofware [20 de Noviembre de 2007, 08:02]

Coinsido con tigo Samuel….
Muy bueno el script! y gracias Xavi por publicarlo…

[ # 12457 ] Comment desde frandy [22 de Diciembre de 2007, 04:34]

samuel, por favor.

En primer lugar es logica elemental que habran personas que haran criticas buenas y malas.

Personalmente, este script es uno de los mejores que he encontrado hasta ahora. Me gusta. Pero habran gente que no. Asi es la vida.

Las criticas malas son buenas, nos ayudan a corregir algunas cosas, o a darnos cuenta de que hay gente que piensa diferente a nosotros.

No hay que llamar a nadie “bola de ignorantes”. No hay que llegar a la descalificacion. Porque en estos comentarios, ningun otro usuario lo ha hecho.

[ # 13504 ] Comment desde Alex [02 de Enero de 2008, 07:51]

¿ como llamo la funcion ?

[ # 13585 ] Comment desde Xavi [03 de Enero de 2008, 09:17]

Pues con algo como:

$ok = validateEmail(”pepe@pepe.com”);

[ # 14305 ] Comment desde khafra [07 de Enero de 2008, 08:00]

muchas gracias ha sido de gran utilidad

[ # 14407 ] Comment desde Xavi [08 de Enero de 2008, 09:07]

A ti ;)

[ # 15004 ] Comment desde frandy [13 de Enero de 2008, 05:35]

¿Por qué será que en algunos servidores no funciona?

[ # 15028 ] Comment desde Xavi [13 de Enero de 2008, 11:39]

Porque cada servidor tiene una configuración distinta, o hasta una implementación del protocolo distinta. Mira en los otros comentarios, que hay variaciones interesantes.

[ # 16226 ] Comment desde kamajii [26 de Enero de 2008, 05:45]

Para el problema de que “checkdnsrr” no está definida en PHP para Windows,…. se puede usar esto. Ponlo al principio de tu código PHP.
—–88—————————————–

por lo demas el código mola……

[ # 18622 ] Comment desde Aitor [19 de Marzo de 2008, 04:22]

Buenas tardes.

A mi me esta dando un error en el primer FOR.

¿alguien me puede ayudar?

[ # 18623 ] Comment desde Xavi [19 de Marzo de 2008, 04:24]

Aitor, qué error te da?

[ # 18630 ] Comment desde Aitor [19 de Marzo de 2008, 05:25]

El error que me da es el siguiente:

Parse error: parse error, unexpected T_LNUMBER, expecting ‘;’ in /var/www/vhost/ecodelarioja.com/home/html/prueba/checkmail.php on line 16

la parte del codigo es: for($i=0;$i 0 && $verify) {

Gracias

[ # 18631 ] Comment desde Xavi [19 de Marzo de 2008, 05:34]

Tienes toda la razón. El script estaba mal posteado. Desgraciadamente, el plugin de colorear el código la lía demasiado.

Está ya arreglado. Recurerda que puedes bajarte el archivo desde uno de los enlaces del artículo.

Saludos.

[ # 18632 ] Comment desde Aitor [19 de Marzo de 2008, 06:05]

Gracias.

Al final me lo he bajado del enlace, pero basta que los tengas mal, para que todo el mundo vaya ahí.

Me gusta mucho.

Gracias

[ # 19631 ] Comment desde Darcon [11 de Abril de 2008, 06:12]

Infinitas Gracias Hermano, el script me ha servido de ayuda de una manera que ni te imaginas….

Te has ganado un visitante mas a tu página,
de nuevo Muchas Gracias

[ # 19745 ] Comment desde Chaveta [13 de Abril de 2008, 11:08]

Xavi, . disculpa la molestia.
El script me dá siempre como respuesta= “1″, . .
tienes idea de porque?

gracias de antemano, . . sl2

[ # 20238 ] Comment desde john [23 de Abril de 2008, 06:04]

Como se implanta el script en un formulario?

[ # 20286 ] Comment desde Aitor [24 de Abril de 2008, 03:25]

Respuesta a Chaveta.

Quita en la parte final el return htmlentities($error); y pon echo $error y asi se mostrará el error. Ami me funcionó así. Por otra parte quita el return false y ponle por ejemplo, echo “dirección de correo verificada”; .

Un saludo

[ # 24532 ] Comment desde Genaro [13 de Junio de 2008, 06:07]

Hola amigos weno yo no se mucho de esto si alguien tiene el scrip listo para subirlo a mi sevidor por fabor si fuecen muy amables me lo envian a mi correo gcmsystem@hotmail.com gracias. que yo puedo darles algun programa interesante, yo tengo algunos por alli.

[ # 42329 ] Comment desde dransa [27 de Octubre de 2008, 07:06]

hola yo no me entero mucho, necesito verificar un correo alguien me puede pasar el scrip listo, os lo agradeceria mucho mi correo es sandra.amaro78@yahoo.com muchas gracias.

[ # 43162 ] Comment desde SPIDY [01 de Noviembre de 2008, 02:39]

EXCELENTE APORTE, REALAMNTE SE AGRADECE LA DISPONIBILIDAD DE PUBLICAR EL CODIGO, GRACIAS, DESDE CHILE.

[ # 59372 ] Comment desde Jesus [25 de Febrero de 2009, 08:25]

De verdad tengo bastante tiempo desarrollando en php, esta funcion a primera vista me parecio excelente, pero no logro que funcione.

Escribe un Comentario





Estadísticas