How to validate the IP of an Emails list to know if they are real or false and if they can receive message?

2

I know there are services that do this, but I would like to know how they do this type of test, to find out if the email is actually 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 ping via server that checks the IP, type:

@servidor.com.br (IP: 200.123.432.231)

I do not 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 this, 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:

@ederwander's answer solved half way, what I'm not getting, is to capture this output he spoke, see in the example below, I'm making the following GET request: [email protected] , using the following class I mounted: / p>

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 this output appears, I believe this is a private value:

220 mx.google.com ESMTP j11si51572042qgd.1 - gsmtp
    
asked by anonymous 19.04.2016 / 15:49

1 answer

6

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

There really is a way to check if an email is valid, every email server needs to have a MX subscribed to DNS to be able to receive messages, therefore anyone can query for which MX domain responds, let's test with gmail, on linux or windows (CMD) soil, type nslookup :

You will get the following output:

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

Perfect now let's define what kind of query we want to do, then type: set type=MX soon then type for example gmail.com , we are talking to see what the MX entries are registered for gmail , I have done here the following answer:

> 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
>

OK, that is, they have several MX entries. If it were a domain that did not exist or did not have MX registered there would be no answer, but notice that every MX register has a different weight, of them for example the one that has less weight, in this case 5 responding by the following address gmail-smtp-in.l.google.com

We can now make a connection to the e-mail send port (25) of this server and send some commands via telnet, here's a real example:

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

After this you will get the following screen:

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

Well start typing commands, (commands need to be exact, you can not go wrong and delete within this telnet connection)

helo hi

As a return you will have:

250 mx.google.com at your service

I liked their message lol, now enter any address even if it does not exist:

mail from: <[email protected]>

will have the following return:

250 2.1.0 OK j11si51572042qgd.1 - gsmtp

Finally type the email you want to check if it exists in this domain:

RCPT TO:<[email protected]>

return will be:

250 2.1.5 OK j11si51572042qgd.1 - gsmtp

Ready a OK very large ...

If the query is for an address q there is no error return 550 :

Follow the 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 does not 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 have demonstrated how to do this in the arm, it is obvious that the "galera" has developed systems that connect via socket on the 25 port and send the commands ...

    
19.04.2016 / 17:42