如何准确判断邮件地址是否存在_java

我总结了几种邮件出现重发、漏发的解释:1.网络;2.防火墙;3.服务器的自我保护,比如防止大批量发送时挂掉或者垃圾邮件,我觉得第三种解释靠谱一些,对于遇到的这些问题在下面的文章中给出了补救措施。

公司邮箱目前使用的是Zimbra,该邮件服务器目前不甚稳定,经常出现重发、漏发问题。经测试,每100封邮件仅可成功发送98封左右,以下是测试数据:
测试用例1:100封,总用时约:16min;实收97封,失败3次,3次错误信息均为:javax.mail.MessagingException: Could not connect to SMTP host
测试用例2:100封,总用时约:16min;实收100封,失败2次,错误同上。加失败重发机制,失败后等待10s重发,最多重发3次;
测试用例3:每发一封,停留10s,总用时32min;实收100封,失败1次,错误同上;重发机制同用例2.
关于MessagingException的问题,可以参考:
javax.mail.MessagingException: Could not connect to SMTP host
  针对这种问题,我增加了邮件重发,

if(sendHtmlMail_(mail)){
    return true;
    } else{
    int i = 0;
    //包含群组邮件,失败不重发
    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;
    }

  但这种机制又产生了新的问题,因邮件服务器不稳定导致在仅发送一次的情况下也会向邮件收件人发送邮件,且同一封邮件的收件人(包括抄送、密送)可能部分收到邮件、部分收不到邮件。
  针对以上的问题,我们将重发机制去除,仅针对不合法邮件(即服务器上不存在的邮件地址)进行剔除,剔除后再进行发送。而对其他原因导致的邮件发送失败不做重发(该问题将通过邮件服务器运维部门向厂商反映)。
   下面是判断邮件是否合法的逻辑:
1.SMTP是工作在两种情况下:一是电子邮件从客户机传输到服务器;二是从某一个服务器传输到另一个服务器 
2.SMTP是个请求/响应协议,命令和响应都是基于ASCII文本,并以CR和LF符结束。响应包括一个表示返回状态的三位数字代码 
3.SMTP在TCP协议25号端口监听连接请求 
4.连接和发送过程 
SMTP协议说复杂也不复杂,说简单如果你懂得Socket。不过现在只是我们利用的就是第一条中说的,从客户机传输到服务器,当我们向一台服务器发送邮件时,邮件服务器会首先验证邮件发送地址是否真的存在于本服务器上。 
5 操作的步骤如下: 
连接服务器的25端口(如果没有邮件服务,连了也是白连) 
发送helo问候 
发送mail from命令,如果返回250表示正确可以,连接本服务器,否则则表示服务器需要发送人验证。 
发送rcpt to命令,如果返回250表示则Email存在 
发送quit命令,退出连接 
基于上面这个逻辑,我们封装邮件服务器形成Socket,发送命令,根据返回值来判断邮件地址是否合法:
具体代码如下:

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 + "\r\n" );
   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;
   }
}

以上是判断邮件地址是否合法的逻辑,如果邮件地址不合法,则将邮件地址从收件人列表中剔除。

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

以上是本文的全部内容,希望大家能够理解,对大家有所帮助。

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索java
smtp
ip地址合法性判断java、java判断mac地址格式、java 邮件地址、java 判断图片url地址、java判断是否是ip地址,以便于您获取更多的相关知识。

时间: 2024-08-25 16:10:49

如何准确判断邮件地址是否存在_java的相关文章

java在网页上面抓取邮件地址的方法_java

本文实例讲述了java在网页上面抓取邮件地址的方法.分享给大家供大家参考.具体实现方法如下: 复制代码 代码如下: import java.io.BufferedReader;  import java.io.InputStreamReader;  import java.net.URL;  import java.util.regex.Matcher;  import java.util.regex.Pattern;    public class h1  {     public stati

VB.NET验证邮件地址的合法性实现代码

一.提出问题 现在,对于用户在Web页面上或电话中给出的Email地址,我们越来越不敢肯定它是否真的有效.在今天这个垃圾邮件泛滥成灾的年代,人们完全有理由舍不得轻易透露Email地址. 另一方面,对于通过正规途径得到的邮件地址,当我们将它用于合法的目的时,也常常要为邮件地址是否有效而烦恼,用户可能有意或无意地写错地址,也可能由于长时间不访问而导致邮箱失效.对于少量的邮件地址,也许可以手工验证其合法性,例如发送测试email:但是,当邮件地址的数量达到数万甚至更多时,手工验证就不可能了,必须用专门

VB.NET验证邮件地址的合法性实现代码_实用技巧

一.提出问题 现在,对于用户在Web页面上或电话中给出的Email地址,我们越来越不敢肯定它是否真的有效.在今天这个垃圾邮件泛滥成灾的年代,人们完全有理由舍不得轻易透露Email地址. 另一方面,对于通过正规途径得到的邮件地址,当我们将它用于合法的目的时,也常常要为邮件地址是否有效而烦恼,用户可能有意或无意地写错地址,也可能由于长时间不访问而导致邮箱失效.对于少量的邮件地址,也许可以手工验证其合法性,例如发送测试email:但是,当邮件地址的数量达到数万甚至更多时,手工验证就不可能了,必须用专门

php 判断是否为有效邮件地址实现代码

 代码如下 复制代码 // 函数名:CheckEmailAddr($C_mailaddr) // 作 用:判断是否为有效邮件地址 // 参 数:$C_mailaddr(待检测的邮件地址) // 返回值:布尔值 // 备 注:无 function CheckEmailAddr($C_mailaddr) { if (!eregi("^[_a-z0-9-]+(.[_a-z0-9-]+)*@[a-z0-9-]+(.[a-z0-9-]+)*$", $C_mailaddr)) //(!ereg(&

Java判断IP地址为内网IP还是公网IP的方法_java

本文实例讲述了Java判断IP地址为内网IP还是公网IP的方法.分享给大家供大家参考.具体分析如下: tcp/ip协议中,专门保留了三个IP地址区域作为私有地址,其地址范围如下: 10.0.0.0/8:10.0.0.0-10.255.255.255 172.16.0.0/12:172.16.0.0-172.31.255.255 192.168.0.0/16:192.168.0.0-192.168.255.255 那么,直接上代码吧: 复制代码 代码如下: public static boolea

编程实现邮件地址有效性检测

编程 编者按:检测邮件地址的有效性可应用于防止垃圾邮件.用户非法注册等方面,本文将以编程的方式进行探讨,相信能给大家一些启示. 编程实现邮件地址有效性检测 文/brain 这个VB6COM组件提供了一项即时邮件查询的功能.它有效的避免了向一个不存在的账户发送邮件的情况.例如,在ASP页面里面检查用户输入的邮件地址是否正确,并避免在你的用户数据库里面存储相关的错误信息. 主要内容 工作原理 让我们首先来看一下这个组件是如何进行工作的. 首先给定一个E-mail地址(例如:someone@somew

js正则表达式验证邮件地址_javascript技巧

我们最经常遇到的验证,就是电子邮件地址验证.网站上常见.各种网页脚本也都常用"正则表达式"(regular expression)对我们输入的电子邮件地址进行验证,判断是否合法.有的还能分解出用户名和域名.现在用JavaScript语言实现一下电子邮件地址验证程序,用的是JavaScript语言的正则表达式库. 效果图: 不合法的情况: 合法的情况: 源代码如下,该网页已在IE.Firefox.Chrome上验证通过: <!DOCTYPE html PUBLIC "-/

java Mail邮件接收工具类_java

下面是一个邮件接收的工具类,有点长!!! public class ReciveMail { private MimeMessage msg = null; private String saveAttchPath = ""; private StringBuffer bodytext = new StringBuffer(); private String dateformate = "yy-MM-dd HH:mm"; public ReciveMail(Mime

php中email邮件地址验证大全集合

CodeIgniter框架邮件地址验证  代码如下 复制代码 /**      * Valid Email      *      * @access  public      * @param   string      * @return  bool      */     function valid_email($str)     {         return ( ! preg_match("/^([a-z0-9+_-]+)(.[a-z0-9+_-]+)*@([a-z0-9-]+.)