How to validate the IP of a list Emails to know if they are real or fake and can receive messages?

Asked

Viewed 903 times

2

I know there are services that do this, but I would like to know how they do this kind of test, to find out if the email is really valid, not only through a PHP filter, for example:

function validEmail($email) {
   if (filter_var($email, FILTER_VALIDATE_EMAIL) !== false) {
       return true;
   } 
   return false;
}

$listaEMails = array(
   'fakemail@gmail',
   '[email protected]',
   '[email protected]',
   '[email protected]',
);

foreach($listaEMails as $k => $email) {
   if (!validEmail($email)) {
       unset($listaEMails[$k]);
   }
}

echo "Emails verdadeiros: <pre>";
print_r($listaEMails);

But using some server ping that checks the IP, like:

@servidor.com.br (IP: 200.123.432.231)

I don’t know if this actually works:

$domain = array_pop(explode("@", $email));

filter_var(gethostbyname($domain), FILTER_VALIDATE_IP);

or

checkdnsrr($domain, "MX");

I think it could be something like, but a way to ping the server?

function nsLookupPing($domain) {
 $app  ="nslookup $domain";
 exec($app, $result);
 if ($result[5] == '' || !isset($result[5])) {
     return false;
 }
 return true;
 }

Edited from here:

The answer of @ederwander solved halfway, what I’m not getting, is to capture this output that he spoke, see in the example below, I’m making the following request GET: [email protected], using the following class I’ve assembled:

class ValidateEmail
{

    private $email;
    private $domain;
    private $socket;

    public function __construct($email)
    {

       $this->email  = $email;
       $domain  = @array_pop(explode("@", $email));
       $this->domain = $domain;
    }

    private function pesoExchanger($a, $b)
    {
        return $a["exchanger_num"] - $b["exchanger_num"];
    }

    private function validEmail()
    {
       if (filter_var($this->email, FILTER_VALIDATE_EMAIL) !== false) {
           return true;
       } 
       return false;
    }

    public function getDomain()
    {
        return $this->domain;
    }

    public function getMail()
    {
        return $this->email;
    }

    public function nsLookupPing()
    {

        if (!$this->validEmail()) {
            //retorna falso, e a mensagem de email inválido
            return array('status'=> false, 'msg' => 'Email inválido');
        }
        //captura o domínio do email
        $domain = $this->getDomain();
        //verifica se o domínio é válido numa conexão do tipo MX
        exec("nslookup -type=mx {$domain}", $result);

        if (!isset($result[4])) {
           //se não houver um retorno válido na linha 4, significa que ele não é um domínio válido
           return array('status'=> false, 'msg' => 'Email com domínio inválido');
        }

        if ($result[4] == '' || preg_match('/No answer/', $result[4])) {
           //se não houver um retorno válido na linha 4, mesmo sendo setado, ele enviará uma resposta de erro 
            return array('status'=> false, 'msg' => 'Email com domínio inválido, motivo: '.$result[4]);
        } 
       //aqui continua para a fase de validação (conforme explicação de: @ederwander)
       $exchanger_num = array();
       //copia o array para uma outra variável e retira as 4 primeiras linhas 
       $n_results = $result;
       unset($n_results[0]);
       unset($n_results[1]);
       unset($n_results[2]);
       unset($n_results[3]);
       //verifica se mesmo removendo as 4 linhas, ainda existe 1 ou mais hosts
       if (!count($n_results)) {
          return array('status'=> false, 'msg' => "Erro de E-mail inválido! Não há um 'mail exchanger' definido para nenhum peso.");
       }
       // faz um laço pegando todos os hosts que contiverem um peso exchanger
       foreach ($n_results as $k => $result_exchanger) {
           if (preg_match('/ exchanger = /', $result_exchanger)) {
              //captura o conteúdo original do servidor e o valor após o exchange
               list($srv_original, $restante) = explode(' exchanger = ', $result_exchanger);
              //quebra nos espaços 
              $first = explode(' ',$restante);
              //remove a informação mail de exchange capturando o primeiro servidor de entrada
              $original_srv  = str_replace('    mail','', $srv_original);
              //lista todos os servidores com seus respectivos pesos
              $srv = $result[4];
              $exchanger_num[] = array(
                                        'srv_original'  => $original_srv ,
                                        'srv_fornecido' => @array_pop(explode(' ',$srv)),
                                        'exchanger_num' => (int) $first[0]
                                 );
           }
       }
      //ordena pelo menor peso 
      usort($exchanger_num, array($this, "pesoExchanger"));

      $other_exchangers = $exchanger_num;
      unset($other_exchangers[0]);
      //retorna todos os servidores, deixando o mais leve como preferido
      return array(
                   'light_exchanger'  => $exchanger_num[0],
                   'other_exchangers' => $other_exchangers,
                   'status'           => true,
                   'msg'              => 'Servidor de e-mail válido'
      );
    } 

    private function extractExchangerLightEmail()
    {
       $data = $this->nsLookupPing();
       if (isset($data['light_exchanger']) && $data['status']) {
          return $data['light_exchanger'];
       }
    }

    public function verifyNSLookupPing()
    {
         //extrai o servidor com peso mais leve
         $data  = $this->extractExchangerLightEmail();
         //verifica se há um servidor fornecido
         if (isset($data['srv_fornecido'])) {
             $host = $data['srv_fornecido'];
             //verifica para ver se existe um cliente de email válido através de um socket tcp, na porta 25
             $fp = stream_socket_client("tcp://{$host}:25", $errno, $errstr, 30);
             if (!$fp) {
               //se ocorrer erro, retorna uma exceção
               return array('status' => false, 'msg'=>"O servidor do E-mail é inválido, erro: $errstr ($errno)");
          } else {
            $result = $this->socketValidation($host, 25);
            if($result) {
               return array('status' => $result['status'], 'msg'=>$result['msg']);
            }
          }

       } 
     return array('status' => false, 'msg'=>"Não ocorreu uma conexão para o Servidor do e-mail");
    }

    private function socketValidation($host, $port = 25)
    {

        $address = gethostbyname($host); 

        $command = "ping -c 1 " . $address;  
        $r = exec($command);  
          if ($r[0]=="r") {        
            $this->socket = socket_create (AF_INET, SOCK_STREAM, 0); 
            if ($this->socket < 0) { 
                $status = false;
                $msg = "Falha de socket: " . socket_strerror($this->socket); 
            } else { 
                $status = true;
                $msg = "O servidor de e-mail é válido!";
            } 
          return array('status' => $status,
                      'msg'     => $msg 
               );
          } else {
             return array('status' =>false,
                      'msg'    => "Não foi possível criar um socket para testar o servidor" 
               );
          }

    }
}

$email = $_GET['email'];

if (isset($email)) {
    $verifyMail = new ValidateEmail($email);
    $saida = $verifyMail->verifyNSLookupPing();
    var_dump($saida);
}

Only in the terminal that appears this output, I believe that this is a private value:

220 mx.google.com ESMTP j11si51572042qgd.1 - gsmtp
  • 2

    Validate IP of an email list ? or know if a particular email address exists ??

  • No, validate if the email can receive message, if it exists and if the server exists?

  • I wonder if you can ping an email (like send something and receive a reply), without having to send a message.

  • 1

    exec("telnet {$host} 25", $result_telnet) This is not the correct way to do, how will you send the rest of the commands? how will you get the return of each line? , You have to work purely with sockets in your code in order to send and catch every expected return....

  • 1

    another detail you are looking for Connected to, there is no such message in telnet return to gmail...

  • I still don’t have a "email" validation itself, only from the server.

  • 2

    @Ivanferrer does not exist secure email validation without sending and monitoring feedback. And even doing so, there may still be some extreme cases of failure.

Show 2 more comments

1 answer

6


Okay I can teach, use it for good, but it smells like SPAM :-(

There are really ways to check if an email is valid, every email server needs to have one MX registered on DNS in order to be able to receive messages, therefore anyone can consult by which MX given domain responds, let’s test with gmail, in solo linux or windows(CMD), type nslookup:

you will get the following exit:

C:\Users\Eder>nslookup
Servidor PadrÒo:  xxxxx
Address:  8.8.8.8

Perfect let’s now define what kind of query we want to do, so type: set type=MX then type for example gmail.com, we are talking to consult which are the entries MX registered to the gmail, I made the following reply here:

> set type=MX
> gmail.com
Servidor:  xxxxxxxxxxx
Address:  8.8.8.8

Não é resposta autoritativa:
gmail.com       MX preference = 20, mail exchanger = alt2.gmail-smtp-in.l.google.com
gmail.com       MX preference = 40, mail exchanger = alt4.gmail-smtp-in.l.google.com
gmail.com       MX preference = 10, mail exchanger = alt1.gmail-smtp-in.l.google.com
gmail.com       MX preference = 5, mail exchanger = gmail-smtp-in.l.google.com
gmail.com       MX preference = 30, mail exchanger = alt3.gmail-smtp-in.l.google.com

gmail.com       nameserver = ns4.google.com
gmail.com       nameserver = ns1.google.com
gmail.com       nameserver = ns3.google.com
gmail.com       nameserver = ns2.google.com
ns1.google.com  internet address = 216.239.32.10
ns2.google.com  internet address = 216.239.34.10
ns3.google.com  internet address = 216.239.36.10
ns4.google.com  internet address = 216.239.38.10
>

Okay there it is, they have several entrances MX, If it were a domain that didn’t exist or didn’t have MX there would be no response, but note that each record MX has a different weight, we will catch any of them for example the one that has less weight, in this case 5 by answering to the following address: gmail-smtp-in.l.google.com

We can now make a connection in the sending port(25) of this server and send some commands by telnet, see a real example:

C:\Users\Eder>telnet gmail-smtp-in.l.google.com 25

after this you will receive the following screen:

220 mx.google.com ESMTP j11si51572042qgd.1 - gsmtp

well start typing commands, (the commands need to be exact, can not err and delete within this telnet connection)

helo hi

how return you will have:

250 mx.google.com at your service

I liked their message lol, now type any address even if there is no:

mail from: <[email protected]>

will have the following return:

250 2.1.0 OK j11si51572042qgd.1 - gsmtp

at last enter the email you want to verify exists in this domain:

RCPT TO:<[email protected]>

the return will be:

250 2.1.5 OK j11si51572042qgd.1 - gsmtp

Ready one OK biggie...

if the query is to a q address there is no error return 550:

Follow the whole process of a valid email:

220 mx.google.com ESMTP j11si51572042qgd.1 - gsmtp
helo hi
250 mx.google.com at your service
mail from: <[email protected]>
250 2.1.0 OK j11si51572042qgd.1 - gsmtp
RCPT TO:<[email protected]>250 2.1.5 OK j11si51572042qgd.1 - gsmtp

And now for an email that doesn’t exist:

220 mx.google.com ESMTP q66si687813qgd.93 - gsmtp
helo hi250 mx.google.com at your service
mail from: <[email protected]>250 2.1.0 OK q66si687813qgd.93 - gsmtp
RCPT TO:<[email protected]>550-5.1.1 The email account that you tried to reach does not exist. Please try
550-5.1.1 double-checking the recipient's email address for typos

I demonstrated how to do this on the arm, it is obvious that the "guys" developed systems that connect via socket in the door 25 and send the commands ...

  • 4

    +1, and remember that currently SMTP services may not confirm at the time whether an address exists or not, and precisely this is used to fight spam. The OK recognizes the mere receipt of the message, but does not serve as proof of existence of the user (in these cases, the server accepts, but returns an email saying that there is no address).

  • That’s right @Bacco the so-called greylist :-)

  • 3

    Just out of curiosity, an extra piece of information: MX is expendable when there is an email service on A or AAAA (although I consider this "DNS economy" to be an extremely dirty practice, it exists).

Browser other questions tagged

You are not signed in. Login or sign up in order to post.