Inicio » Programación » pyEmailChecker: Comprobar si un email existe con Python

pyEmailChecker: Comprobar si un email existe con Python

En esta entrada, tal y como indica su título, os voy a mostrar un pequeño script de Python mediante el cuál podemos saber si una cuenta de correo existe.

Además, lo vamos a comprobar sin hacer uso del comando VRFY del protocolo SMTP, que no tiene por qué estar disponible en todos los servidores de correo.

Este script con este tipo de comprobación puede servirnos para descartar direcciones de correo que vamos encontrando en auditorías, o para completar scripts que generen posibles cuentas de correo a partir de diccionarios, combinaciones de nombre y apellidos, iniciales…

Si tenemos automatizada la generación de patrones podemos automatizar también la comprobación de si alguno existe realmente.

Respecto al código, el funcionamiento es sencillo. Al script le pasamos un par de parámetros: una cuenta de correo a comprobar (obligatorio) y si queremos que muestre el proceso de comprobación por pantalla o sólo los resultados mediante el parámetro «debug» (true mostrará el proceso, false no).

El script lo primero que hace es listar todos los servidores MX del dominio de la cuenta de correo que le hemos proporcionado para, recorriendo todos los que encuentre, comprobar si la cuenta existe en alguno de ellos.

Hasta el momento, todas las pruebas han sido satisfactorias, pero si encontráis alguna pega hacédmelo saber.

Aquí os dejo un vídeo donde se puede ver la ejecución del script con una cuenta que no existe, con una cuenta que sí existe y cómo se ve la depuración cuando proporcionamos el parámetro «–debug True«.

Para abrirlo en YouTube directamente puedes pulsar el título del video o aquí.

Vídeo demostrativo pyEmailChecker

Por último, os dejo el código fuente del script, aunque ya sabéis que mi código no es precisamente «depurado» ya que voy cogiendo un poco de aquí y otro poco de allá y luego me lo compongo a mi gusto.

Un saludo y hasta la próxima.

(Si estáis con dispositivos móviles, poned la pantalla en horizontal y ajustará el código o haced uso de los botones «Raw«, «Copy» o «Extern» de la esquina superior derecha)

#!/usr/bin/python
import smtplib
import DNS
import socket
import argparse


def get_mx(hostname):
    try:
        servidor_mx = DNS.mxlookup(hostname)
    except ServerError as e:
        if e.rcode == 3 or e.rcode == 2:  # NXDOMAIN (Non-Existent Domain) or SERVFAIL
            servidor_mx = None
        else:
            raise
    return servidor_mx


def validar_email(email, debug=False):
    try:
        hostname = email[email.find('@') + 1:]
        mx_hosts = get_mx(hostname)
        if mx_hosts is None:
            print('No se encuentra MX para el dominio {}'.format(hostname))
            return None
        for mx in mx_hosts:
            try:
                print('Servidor {}'.format(mx[1]))
                print('Cuenta {}'.format(email))
                servidor = smtplib.SMTP(timeout=10)
                servidor.connect(mx[1])
                servidor.set_debuglevel(debug)
                status, _ = servidor.helo()
                if status != 250:
                    servidor.quit()
                    continue
                servidor.mail('')
                status, _ = servidor.rcpt(email)
                if status == 250:
                    servidor.quit()
                    return True
                servidor.quit()
            except smtplib.SMTPServerDisconnected:  # Server not permits verify user
                if debug:
                    print('{} disconected.'.format(mx[1]))
            except smtplib.SMTPConnectError:
                if debug:
                    print('Unable to connect to {}.'.format(mx[1]))
        return False
    except (ServerError, socket.error) as e:
        print('ServerError or socket.error exception raised ({}).'.format(e))
        return None


ServerError = DNS.ServerError

if __name__ == "__main__":
    PARSER = argparse.ArgumentParser(
        description="""DESCRIPCIÓN: Este script comprueba si una dirección de correo existe en un MX (intercambiador de correo).""", usage="\n./main.py email@address \n./main.py -h for help", epilog="""Autor : Oscar Navarrete, onavarrete@protonmail.com""")
    PARSER.add_argument('email', help='Dirección de email a comprobar')
    PARSER.add_argument('--debug', required=False, default=False, type=bool, help='Mostrar mensajes por pantalla (True/False)')
    USERSARGS = PARSER.parse_args()

    resultado = validar_email(USERSARGS.email, USERSARGS.debug)
    if resultado:
        print('La cuenta existe')
    elif resultado is None:
        print('No se puede determinar')
    else:
        print('La cuenta no existe')


12 comentarios

  1. Hola que buen aporte, solamente tengo el problema que me da timeout para cualquier correo y no se porqué.

    Gracias

    • Buenas tardes Arnold.
      ¿Has probado a conectar a otros servidores de correo o usando telnet? Coge un servidor de correo que sepas que funciona en SMTP puerto 25 por ejemplo, y haz «telnet direccióndelservidor 25» para conectar por telnet a ver si conecta. Con esa prueba puedes probar el puerto 25, pero puedes hacerlo para el resto de puertos. Si no obtienes respuesta para ningún servidor y puerto, tal vez tengas «capada» la conexión. Hay proveedores como Euskaltel que tienen limitadas las conexiones por el puerto 25 a sus propios servidores de correo o tal vez tu IP esté en una lista negra y te rechacen las conexiones los servidores de correo. Hay muchas opciones por las que podría no funcionar pero eres tú quién puede comprobarlas ya que depende de tu conexión directamente. Es raro que te de timeout para todos los servidores que pruebes (más que nada porque son servidores que están funcionando seguro ya que los estás consultando en los MX de los dominios concretos) y que el problema no esté en tu conexión. Un saludo.

  2. una pregunta este script valida todos los correos electronicos o solo valida los correos que realmente existen

    • Buenas noches.

      No entiendo bien qué quieres decir. El script comprueba si el correo que le pasas como parámetro existe en cualquiera de los servidores de correo que estén dados de alta como MX (intercambiadores de correo) del dominio de dicha cuenta. Si existe, lo dice y si no existe también.

      Un saludo.

  3. Gran artículo! ¿Cuál es el paquete que usas para >>import DNS? He probado >>pip3 install py3dns , pero no consigo que me funcione.

    • Buenas noches Joaquín.
      Pues precisamente uso ese, py3dns en su versión 3.2.1 para ser exactos. Está instalado desde la gestión de paquetes del proyecto dentro de PyCharm, pero dicho gestor también usa pip para instalar los paquetes así que no hay nada raro.
      Comprueba que tienes todos los paquetes necesarios.
      Un saludo.
      Paquetes necesarios

      • hola buenas, sería recomendable el uso de algún proxy si se pretende comprobar una gran cantidad de correos? un saludo y gracias! buen artículo!

        • Buenas noches. Se me había pasado responderte. En principio un servidor de correo tiene que tratar con muchas conexiones, así que por ese motivo no seríamos baneados. Otra cosa sería provocar muchos errores o intentos de ejecución de comandos sospechosos que sí podríamos ser bloqueados. Pero simplemente por intentar entregar correo en buzones inexistentes sería raro. Si hay algún otro sistema previo que compruebe conexiones por minuto, misma IP o similares también podría filtrarnos. Aún así, las pruebas siempre, siempre con gaseosa, ya tu sabe. 😉

          • Buenos días,

            Maravilloso código. ¿Cómo podría comprobar una lista grande de correos? Es decir, ¿cómo podría comprobar más de un correo a la vez?

            Gracias,

          • Hola. Se puede cambiar el parámetro del email por una lista separada por comas, por ejemplo. Luego, a la hora de comprobar, se recorre la lista con un bucle y solucionado. Un saludo.

Deja un comentario

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

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.