最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

如何準確判斷郵件地址是否存在

 更新時間:2015年07月23日 11:34:17   作者:gaochaojs  
本文介紹了如何判斷郵件地址是否存在的方法,具有很高的使用價值,提高了工作效率

我總結了幾種郵件出現(xiàn)重發(fā)、漏發(fā)的解釋:1.網絡;2.防火墻;3.服務器的自我保護,比如防止大批量發(fā)送時掛掉或者垃圾郵件,我覺得第三種解釋靠譜一些,對于遇到的這些問題在下面的文章中給出了補救措施。

公司郵箱目前使用的是Zimbra,該郵件服務器目前不甚穩(wěn)定,經常出現(xiàn)重發(fā)、漏發(fā)問題。經測試,每100封郵件僅可成功發(fā)送98封左右,以下是測試數(shù)據(jù):
測試用例1:100封,總用時約:16min;實收97封,失敗3次,3次錯誤信息均為:javax.mail.MessagingException: Could not connect to SMTP host
測試用例2:100封,總用時約:16min;實收100封,失敗2次,錯誤同上。加失敗重發(fā)機制,失敗后等待10s重發(fā),最多重發(fā)3次;
測試用例3:每發(fā)一封,停留10s,總用時32min;實收100封,失敗1次,錯誤同上;重發(fā)機制同用例2.
關于MessagingException的問題,可以參考:
javax.mail.MessagingException: Could not connect to SMTP host
  針對這種問題,我增加了郵件重發(fā),

if(sendHtmlMail_(mail)){
    return true;
    } else{
    int i = 0;
    //包含群組郵件,失敗不重發(fā)
    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;
    }

  但這種機制又產生了新的問題,因郵件服務器不穩(wěn)定導致在僅發(fā)送一次的情況下也會向郵件收件人發(fā)送郵件,且同一封郵件的收件人(包括抄送、密送)可能部分收到郵件、部分收不到郵件。
  針對以上的問題,我們將重發(fā)機制去除,僅針對不合法郵件(即服務器上不存在的郵件地址)進行剔除,剔除后再進行發(fā)送。而對其他原因導致的郵件發(fā)送失敗不做重發(fā)(該問題將通過郵件服務器運維部門向廠商反映)。
   下面是判斷郵件是否合法的邏輯:
1.SMTP是工作在兩種情況下:一是電子郵件從客戶機傳輸?shù)椒掌?;二是從某一個服務器傳輸?shù)搅硪粋€服務器 
2.SMTP是個請求/響應協(xié)議,命令和響應都是基于ASCII文本,并以CR和LF符結束。響應包括一個表示返回狀態(tài)的三位數(shù)字代碼 
3.SMTP在TCP協(xié)議25號端口監(jiān)聽連接請求 
4.連接和發(fā)送過程 
SMTP協(xié)議說復雜也不復雜,說簡單如果你懂得Socket。不過現(xiàn)在只是我們利用的就是第一條中說的,從客戶機傳輸?shù)椒掌?,當我們向一臺服務器發(fā)送郵件時,郵件服務器會首先驗證郵件發(fā)送地址是否真的存在于本服務器上。 
5 操作的步驟如下: 
連接服務器的25端口(如果沒有郵件服務,連了也是白連) 
發(fā)送helo問候 
發(fā)送mail from命令,如果返回250表示正確可以,連接本服務器,否則則表示服務器需要發(fā)送人驗證。 
發(fā)送rcpt to命令,如果返回250表示則Email存在 
發(fā)送quit命令,退出連接 
基于上面這個邏輯,我們封裝郵件服務器形成Socket,發(fā)送命令,根據(jù)返回值來判斷郵件地址是否合法:
具體代碼如下:

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總結篇系列:Java泛型詳解

    Java總結篇系列:Java泛型詳解

    下面小編就為大家?guī)硪黄狫ava總結篇系列:Java泛型詳解。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-09-09
  • Java中json使用方法_動力節(jié)點Java學院整理

    Java中json使用方法_動力節(jié)點Java學院整理

    JSON(JavaScript Object Notation) 是一種輕量級的數(shù)據(jù)交換格式, json是個非常重要的數(shù)據(jù)結構,在web開發(fā)中應用十分廣泛。下面通過本文給大家講解Java中json使用方法,感興趣的朋友一起看看吧
    2017-07-07
  • 深入分析Java異常

    深入分析Java異常

    本篇文章給大家詳細分享了關于Java異常的相關知識點,對此有需要的朋友跟著學習下吧。
    2018-05-05
  • js判斷是否是移動設備登陸網頁的簡單方法

    js判斷是否是移動設備登陸網頁的簡單方法

    這篇文章主要介紹了js判斷是否是移動設備登陸網頁的簡單方法,需要的朋友可以參考下
    2014-02-02
  • Java使用反射來獲取泛型信息示例

    Java使用反射來獲取泛型信息示例

    這篇文章主要介紹了Java使用反射來獲取泛型信息,結合實例形式分析了java基于反射操作泛型信息的相關實現(xiàn)技巧與注意事項,需要的朋友可以參考下
    2019-07-07
  • 使用WebSocket實現(xiàn)即時通訊(一個群聊的聊天室)

    使用WebSocket實現(xiàn)即時通訊(一個群聊的聊天室)

    這篇文章主要為大家詳細介紹了使用WebSocket實現(xiàn)即使通訊,實現(xiàn)一個群聊的聊天室,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-03-03
  • springboot實現(xiàn)極驗校驗的項目實踐

    springboot實現(xiàn)極驗校驗的項目實踐

    在系統(tǒng)業(yè)務中,需要想客戶發(fā)送手機驗證碼,進行驗證后,才能提交,本文主要介紹了springboot實現(xiàn)極驗校驗的項目實踐,具有一定的參考價值,感興趣的可以了解一下
    2023-09-09
  • SpringBoot配置加載,各配置文件優(yōu)先級對比方式

    SpringBoot配置加載,各配置文件優(yōu)先級對比方式

    這篇文章主要介紹了SpringBoot配置加載,各配置文件優(yōu)先級對比方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-08-08
  • 關于springboot2整合lettuce啟動卡住問題的解決方法

    關于springboot2整合lettuce啟動卡住問題的解決方法

    Lettuce和Jedis的都是連接Redis Server的客戶端程序,下面這篇文章主要給大家介紹了關于springboot2整合lettuce啟動卡住問題的解決方法,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考下
    2021-12-12
  • Spring常用一些工具類實例匯總

    Spring常用一些工具類實例匯總

    這篇文章主要介紹了Spring常用一些工具類實例匯總,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-12-12

最新評論

杭锦后旗| 常宁市| 光山县| 山阳县| 抚顺市| 化德县| 灌南县| 建瓯市| 东海县| 克什克腾旗| 朝阳市| 锡林浩特市| 龙井市| 天台县| 富裕县| 连山| 阿拉尔市| 靖州| 治县。| 桐乡市| 永宁县| 小金县| 海南省| 柳河县| 榆林市| 云安县| 洪洞县| 习水县| 兴城市| 得荣县| 吉林省| 平江县| 泾川县| 慈利县| 米脂县| 左云县| 漯河市| 临沧市| 呼玛县| 巴东县| 简阳市|