How to determine the existence of an email address

  • 2020-04-01 04:04:08
  • OfStack

I have summarized several explanations for the retransmission and omission of emails: 1. Network; 2. 2. Firewall; 3. The self-protection of the server, such as preventing the failure or spam in the mass delivery, I think the third explanation is more reliable. The following article provides remedial measures for these problems.

Zimbra is currently used in the company's mailbox. The mail server is unstable and often has problems of resending and missing. According to the test, only about 98 emails can be successfully sent for every 100 emails. The following is the test data:
Test cases 1:100, the total time of about: 16min; Paid-in 97 letters, fail three times, 3 times error message are: javax.mail. Mail. MessagingException: Could not connect to SMTP host
Test cases 2:100, the total time of about: 16min; Received 100, failed 2 times, error same as above. Add failure retransmission mechanism, wait for 10s retransmission after failure, the most multiple 3 times;
Test case 3: each time, stay 10s, the total time of 32min; Received 100, failed 1 time, error is the same as above; Replay mechanism with use case 2.
For MessagingException, please refer to:
Javax.mail. Mail. MessagingException: Could not connect to SMTP host
For this kind of problem, I added the re-email,


if(sendHtmlMail_(mail)){
    return true;
    } else{
    int i = 0;
    //Contains group email, failure not resend
    boolean isNeedRe = isNeedRe(mail);
    while(!sendHtmlMail_(mail) && isNeedRe && i < 10){
    try {
    i++;
    Thread.sleep(1000*60);
    } catch (InterruptedException e) {
    LOGGER.error("resend mail error", e);
    }
    }
    return true;
    }

However, this mechanism has created a new problem, because the unstable mail server will send mail to the recipients of the mail only once, and the recipients of the same mail (including cc, BCC) may receive some mail and some may not.
For the above problems, we will remove the resend mechanism, only for illegal mail (that is, the mail address does not exist on the server) to eliminate, after the elimination of the send. There is no resend for mail failure caused by other reasons (the problem will be reported to the vendor through the mail server operations department).
Here's the logic to determine if an email is legitimate:
1.SMTP is working in two situations: one is the transfer of E-mail from the client to the server; Two is from one server to another server  
2.SMTP is a request/response protocol. Commands and responses are based on ASCII text and end with CR and LF. The response includes a three-digit code & PI that represents the return status;
3.SMTP listens for connection request & NBSP on TCP port 25;
Connect and send process  
SMTP protocol says complex is not complex, said simple if you know Socket. But for now we're just taking advantage of what we said in the first one, which is that we're transferring from the client to the server, and when we send a message to a server, the mail server first verifies that the mail address actually exists on the server.  
The steps are as follows:
Connect to port 25 of the server (or, if there is no mail service, nothing)  
Send helo greetings  
Send the mail from command. If it returns 250, you can connect to the server. Otherwise, the server needs to be authenticated by the sender.  
Send the RCPT to command and if 250 is returned the Email exists  
Send the quit command to exit the connection  
Based on the above logic, we package the mail server to form a Socket, send the command, according to the return value to determine whether the mail address is legal:
The specific code is as follows:


import java.io.*;
import java.net.*;
import java.util.*;
import javax.naming.*;
import javax.naming.directory.*;
 
public class SMTPMXLookup {
  private static int hear( BufferedReader in ) throws IOException {
   String line = null;
   int res = 0;
 
   while ( (line = in.readLine()) != null ) {
     String pfx = line.substring( 0, 3 );
     try {
      res = Integer.parseInt( pfx );
     }
     catch (Exception ex) {
      res = -1;
     }
     if ( line.charAt( 3 ) != '-' ) break;
   }
 
   return res;
   }
 
  private static void say( BufferedWriter wr, String text )
   throws IOException {
   wr.write( text + "rn" );
   wr.flush();
 
   return;
   }
   private static ArrayList getMX( String hostName )
     throws NamingException {
   // Perform a DNS lookup for MX records in the domain
   Hashtable env = new Hashtable();
   env.put("java.naming.factory.initial",
       "com.sun.jndi.dns.DnsContextFactory");
   DirContext ictx = new InitialDirContext( env );
   Attributes attrs = ictx.getAttributes
              ( hostName, new String[] { "MX" });
   Attribute attr = attrs.get( "MX" );
 
   // if we don't have an MX record, try the machine itself
   if (( attr == null ) || ( attr.size() == 0 )) {
    attrs = ictx.getAttributes( hostName, new String[] { "A" });
    attr = attrs.get( "A" );
    if( attr == null )
      throw new NamingException
           ( "No match for name '" + hostName + "'" );
   }
     // Huzzah! we have machines to try. Return them as an array list
   // NOTE: We SHOULD take the preference into account to be absolutely
   //  correct. This is left as an exercise for anyone who cares.
   ArrayList res = new ArrayList();
   NamingEnumeration en = attr.getAll();
 
   while ( en.hasMore() ) {
    String mailhost;
    String x = (String) en.next();
    String f[] = x.split( " " );
    // THE fix *************
    if (f.length == 1)
      mailhost = f[0];
    else if ( f[1].endsWith( "." ) )
      mailhost = f[1].substring( 0, (f[1].length() - 1));
    else
      mailhost = f[1];
    // THE fix *************      
    res.add( mailhost );
   }
   return res;
   }
 
  public static boolean isAddressValid( String address ) {
   // Find the separator for the domain name
   int pos = address.indexOf( '@' );
 
   // If the address does not contain an '@', it's not valid
   if ( pos == -1 ) return false;
 
   // Isolate the domain/machine name and get a list of mail exchangers
   String domain = address.substring( ++pos );
   ArrayList mxList = null;
   try {
    mxList = getMX( domain );
   }
   catch (NamingException ex) {
    return false;
   }
 
   // Just because we can send mail to the domain, doesn't mean that the
   // address is valid, but if we can't, it's a sure sign that it isn't
   if ( mxList.size() == 0 ) return false;
 
   // Now, do the SMTP validation, try each mail exchanger until we get
   // a positive acceptance. It *MAY* be possible for one MX to allow
   // a message [store and forwarder for example] and another [like
   // the actual mail server] to reject it. This is why we REALLY ought
   // to take the preference into account.
   for ( int mx = 0 ; mx < mxList.size() ; mx++ ) {
     boolean valid = false;
     try {
       int res;
       //
       Socket skt = new Socket( (String) mxList.get( mx ), 25 );
       BufferedReader rdr = new BufferedReader
        ( new InputStreamReader( skt.getInputStream() ) );
       BufferedWriter wtr = new BufferedWriter
        ( new OutputStreamWriter( skt.getOutputStream() ) );
 
       res = hear( rdr );
       if ( res != 220 ) throw new Exception( "Invalid header" );
       say( wtr, "EHLO rgagnon.com" );
 
       res = hear( rdr );
       if ( res != 250 ) throw new Exception( "Not ESMTP" );
 
       // validate the sender address       
       say( wtr, "MAIL FROM: <tim@orbaker.com>" );
       res = hear( rdr );
       if ( res != 250 ) throw new Exception( "Sender rejected" );
 
       say( wtr, "RCPT TO: <" + address + ">" );
       res = hear( rdr );
 
       // be polite
       say( wtr, "RSET" ); hear( rdr );
       say( wtr, "QUIT" ); hear( rdr );
       if ( res != 250 )
        throw new Exception( "Address is not valid!" );
 
       valid = true;
       rdr.close();
       wtr.close();
       skt.close();
     }
     catch (Exception ex) {
      // Do nothing but try next host
      ex.printStackTrace();
     }
     finally {
      if ( valid ) return true;
     }
   }
   return false;
   }
 
  public static void main( String args[] ) {
   String testData[] = {
     "real@rgagnon.com",
     "you@acquisto.net",
     "fail.me@nowhere.spam", // Invalid domain name
     "arkham@bigmeanogre.net", // Invalid address
     "nosuchaddress@yahoo.com" // Failure of this method
     };
 
   for ( int ctr = 0 ; ctr < testData.length ; ctr++ ) {
    System.out.println( testData[ ctr ] + " is valid? " +
       isAddressValid( testData[ ctr ] ) );
   }
   return;
   }
}

The above is the logic to determine whether the email address is legal or not. If the email address is not legal, the email address is removed from the recipient list.


private static String[] removeInvalidateAddress(String[] addresses, String mailFrom) 
  {   
    ArrayList<String> validateAddresses = new ArrayList<String>(); 
    String normalAddress = null; 
    int code; 
      
    SMTPTransport smptTrans = null; 
    if(StringUtils.isEmpty(mailFrom) || null == addresses) 
    { 
      return new String[0]; 
    } 
    String sendCmd = "MAIL FROM:" + normalizeAddress(mailFrom); 
    try 
    { 
    smptTrans = (SMTPTransport)sendSession.getTransport("smtp"); 
    smptTrans.connect(); 
    code = smptTrans.simpleCommand(sendCmd); 
    if(code != 250 && code != 251) 
    { 
      logger.error("send from invalidate" + mailFrom); 
    } 
    else 
    { 
      for(String address : addresses) 
      { 
        normalAddress = normalizeAddress(address); 
        String cmd = "RCPT TO:" + normalAddress; 
    code = smptTrans.simpleCommand(cmd); 
    if(code == 250 || code == 251) 
    { 
      validateAddresses.add(address); 
    } 
      } 
    } 
    } 
    catch(MessagingException e) 
    { 
      logger.error("Validate mail address error. send from " + mailFrom, e); 
    } 
      
    String[] result = validateAddresses.toArray(new String[validateAddresses.size()]); 
    return result; 
  } 
    
  private static String normalizeAddress(String addr)  
  { 
    if ((!addr.startsWith("<")) && (!addr.endsWith(">"))) 
      return "<" + addr + ">"; 
    else 
      return addr; 
  }

The above is the entire content of this article, I hope you can understand, to help you.


Related articles: