JWorld@TW the best professional Java site in Taiwan
      註冊 | 登入 | 全文檢索 | 排行榜  

» JWorld@TW » EJB / 其它Java EE 討論區 » JavaMail  

按列印兼容模式列印這個話題 列印話題    把這個話題寄給朋友 寄給朋友   
reply to postflat modego to previous topicgo to next topic
話題被移動
該話題已被移動 - browser , 2004-07-28 02:57
如果您尚不清楚該話題被移動的原因,請參考論壇規則以及本版公告或者聯系本版版主。
本主題所含的標籤
無標籤
作者 自行設計 JavaMail 的中文解碼程式
精靈





發文: 86
積分: 7
於 2004-07-26 02:02 user profilesend a private message to userreply to postreply to postsearch all posts byselect and copy to clipboard. 
ie only, sorry for netscape users:-)add this post to my favorite list
以下的邏輯,用於解決 From(寄件者), To(收件者), Cc(副本), Bcc(祕件副本) 及 Subject(主旨) 的中文亂碼問題:

中文亂碼問題的發生原因,大部分來自非正規的寄信軟體,尤其廣告信造成的亂碼問題最多。

邏輯如下:
1.先判斷 mail header 對應 From, To, Cc, Bcc, Subject 的資訊中,是否有設定 charset。
可使用 String header[] = msg.getHeader("From"); String header[] = msg.getHeader("To"); ...來取得 mail header 的資訊。
通常只要判斷 header[0] 的字串即可,判斷有無設定 charset,可使用以下的指令:
1
2
3
4
5
6
  if ( header[0].indexOf("=?") != -1 ) {
    // 有設定 charset
  }
  else {
    // 沒有設定 charset
  }

mail header 字串中,若有中文,正常會以 =? 作為字串的開始,接著是 "big5" , "gb2312" ... 的 charset name. 然後緊接著是 "?B?" or "?Q?" 代表字串的編碼規則。

2.假如 mail header 中沒有設定 charset,遇到這種狀況,JavaMail API 會將字串當作 ISO8859 charset 來處理,所以,你看到的肯定是亂碼。由於完全沒有 charset 可供參考,你唯一能作的事,就是將字串由 ISO8859 轉為 Big5 or GB2312.
1
return new String( source_str.getBytes("8859_1"), "Big5");


3.如果在 mail header 中有設定 charset,一般來說,不太會出現中文亂碼,但假如後續的編碼有任何的例外,JavaMail API 會莫名其妙的不解析字串,直接以 =?Big5?B?AKLJXJAIILASD 一大堆的 ASCII Code 回傳,造成中文顯示不出來。
所以,保險起見,你必須再次判斷字串中是否仍有 "=?"。
1
2
3
4
5
6
  if ( source_str.indexOf( "=?" ) != -1 ) {
    // 很不幸,JavaMail API 解不出,你必須自己解了
  }
  else {
    // JavaMail API 解的是正確的,無須再解一次。
  }


4. 假如,JavaMail API 解不出來,比較常見的是採用 "?Q?" 的編碼,此時,你必須自己設計解碼程式了,所以,先判斷字串的編碼規則是不是 "?Q?"。
1
2
3
4
5
6
7
 if ( source_str.indexOf("?Q?") != -1 ) {
    // 你必須自己解 ?Q? 的字串
  }
  else { // 如果不是 "?Q?"
    // 強迫使用 MimeUtility.decodeText() 去解,通常都會解成功。
    return MimeUtility.decodeText(source_str);
  }


5. "?Q?" 的解碼程式如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
  /**
   * 針對某些用 ?Q? 的編碼,但編的不正確的字串進行解析.
   * 某些狀況,javamail api 無法解析使用 ?Q? 編碼的字串.
   * 無法解析的原因沒有深入去研究,但以此 method 重新解碼之後,
   * 字串就可正常顯示了。
   * 此 method 會先檢查字串中是否含有  "?Q?" 的資訊,若沒有,則不進行解析,回傳原字串.
   * "?Q?" 的編碼規則如下:
   * 假如遇到字串中有 '=' 字元,代表接下來的二個字元為 Hex code,必須將此二個字元組成的字串,
   * 解析還原為 byte. 若字元前面沒有 '=' 的字元,則必須將該字元的 ASCII Code 轉為 byte.
   * 整個字串最後會組裝成一個 byte[],請依據所要的字串編碼, 採用 new String(byte[], enc);
   * 將 byte[] 轉成字串。
   *
   * @param sSur
   * @return
   */
  public static String decodeQ(String sSur) {
    try {
      byte bTag[] = new byte[sSur.length()];
      int ndx = sSur.indexOf("?Q?");
      if (ndx == -1) return sSur;
      StringBuffer sbChar = new StringBuffer(2);
      int nbc = 0;
      for (int j = (ndx + 3); j < sSur.length(); j++) {
        if (sSur.charAt(j) == '=') {
          sbChar.setLength(0);
          if (sSur.length() > (j + 1)) sbChar.append(sSur.charAt(j + 1));
          else break;
          if (sSur.length() > (j + 2)) sbChar.append(sSur.charAt(j + 2));
          else break;
          bTag[nbc] = (byte) Integer.parseInt(sbChar.toString(), 16);
          nbc++;
          j += 2;
        }
        else {
          bTag[nbc] = (byte) sSur.charAt(j);
          nbc++;
        }
      }
      if (nbc > 0) return new String(bTag, 0, nbc, MailOpt.DEFAULT_CHARSET);
      return sSur;
    }
    catch (Exception e) {
      return sSur;
    }
  }

以上的說明僅是概要,詳細的內容請參閱附件,有完整的解碼程式。
使用方式如下:
取主旨的方法:
1
2
3
4
5
6
7
public static String getSubject(Message msg) {
  String subject = msg.getSubject();
  if (MailUtil.isEmpty(subject)) return "無主旨";
  String header[] = msg.getHeader("Subject");
  if (header == null)  return "無主旨";
  return MailUtil.decodeString(subject, header[0]);
}


取寄件者的方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public static String getFrom(Message msg) {
  String from_header[] = msg.getHeader("From");
  if (from_header == null) return "";
  Address from[] = msg.getFrom();
  if (from == null) return "";
  String personal = "";
  if ((from[0] instanceof InternetAddress) ) {
    personal = ((InternetAddress) from[0]).getPersonal();
  }
  if (MailUtil.isEmpty(personal) != true ) {
    personal = MailUtil.decodeString(personal, from_header[0]);
  }
  else personal = "";
  if (personal.length() > 0) {
    return personal + "<" + ((InternetAddress) from[0]).getAddress() + ">";
  }
  // 有時候,某些爛廣告信,會沒有 mail address 而只有中文.
  // 所以,還是必須進行解碼比較不會有亂碼產生.
  return MailUtil.decodeString(from[0].toString(), from_header[0]);
}


至於收件者、副本等,請仿照寄件者的作法,逐一進行解碼。

ps: MailUtil.java 中,有用到一個 DEFAULT_CHARSET,預設是 Big5 碼,理論上應該由 =?xxx 中取出該字串的 charset,但由於此程式實作於 webmail,網頁上僅能顯示出一種 charset,所以固定設為 Big5 編碼。

MailUtil.java (7.86k)


reply to postreply to post
話題樹型展開
人氣 標題 作者 字數 發文時間
9762 自行設計 JavaMail 的中文解碼程式 精靈 4044 2004-07-26 02:02
6650 Re:自行設計 JavaMail 的中文解碼程式 精靈 325 2004-07-26 02:24
4968 Re:自行設計 JavaMail 的中文解碼程式 GuanChih 712 2004-10-18 17:39
6064 Re:自行設計 JavaMail 的中文解碼程式 hkdennis2k 775 2004-10-23 11:17
» JWorld@TW »  EJB / 其它Java EE 討論區 » JavaMail

reply to postflat modego to previous topicgo to next topic
  已讀文章
  新的文章
  被刪除的文章
Jump to the top of page

JWorld@TW 本站商標資訊

Powered by Powerful JuteForum® Version Jute 1.5.8