1. 程式人生 > >非典型 JavaMail 郵件附件名亂碼問題

非典型 JavaMail 郵件附件名亂碼問題

------------  記一個JavaMail 附件亂碼的問題      說到亂碼,很多人都遇到過,“哎呀,你這個編碼是不是UTF-8!”,“你這個會不會作業系統不一致導致的?”,“肯定是兩邊編碼不一致”。不過我們今天說的問題,還真不是這個問題導致的。 問題    用JavaMail 發郵件,帶上附件,閃電郵客戶端收到後,附件名有時亂碼,有時非亂碼。檢視Java端程式碼:
                 String name = MimeUtility.encodeText(name, null) + ".xlsx";
		messageBodyPart.setFileName(name);
貌似已經做過編碼轉換了。 令人感到奇怪的是,稍微改變附件名,亂碼就消失了。 發現    收集各種資訊的時候,突然發現 Ubuntu的小夥伴 在 ThunderBird下收郵件表示沒有異常,Mac黨表示自帶的郵件工具收件也沒有問題。那是不是作業系統字元編碼問題呢? 可是遺憾的是,在網頁版上,依舊是亂碼。 這時候初步懷疑是郵件系統不相容的問題了,來看郵件原始碼:
Content-Type: application/octet-stream; 
	name*0="=?utf-8?B?5rWL6K+V5qCH6aKYLS0tMDAx5oiR6KaB5LiK?==?utf-8?B?5"; 
	name*1
="a2mQUJDREXvvIzlkKzor7TopoHotrPlpJ/plb8=?=.xlsx" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename*0="?utf-8?B?5rWL6K+V5qCH6aKYLS0tMDAx5oiR6KaB5LiK?==?utf-8?B?5"; filename*1="a2mQUJDREXvvIzlkKzor7TopoHotrPlpJ/plb8=?=.xlsx"
這串就是 有些系統亂碼有些系統 正常顯示的 郵件原始碼。。 對比在郵件客戶端上的非亂碼郵件:
Content-Type: application/octet-stream; name="=?utf-8?B?5rWL6K+V?=.xlsx"
Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="=?utf-8?B?5rWL6K+V?=.xlsx"
 filename*0,filename*1 和 filename 的區別,猜測也許就是郵件客戶端不支援這種filename*0,filename*1 協議導致的問題。 分析   有了以上的想法,就開始來看原始碼。    MimeBodyPart 這個類中的 setFileName 方法 用到一個 ParameterList 在ParameterList 的 toString 類中找到下面一段:
   if (v instanceof MultiValue) {
		// ....
			ns = name + i + "*";
		//...
		}
	    } else if (v instanceof Value) {
		/// ...
	    } else {
		
		if (value.length() > 60 &&
				splitLongParameters && encodeParameters) {
		    int seg = 0;
		    name += "*";
		    /// ....
		}
這個類在郵件附件屬於 MultiValue 會把 名字用name + i 隔開 ,在名字大於 60個字元的時候也會主動截斷,這也就是 javamail 中 附件的命名規則,名字太長會被截斷~~! 中文在base64 加密後,超過60個字元那是妥妥的有可能。這種截斷檔名的模式在某些客戶端,並不能很好的支援。 解決   解決就很容易了, 程式碼裡有 splitLongParameters 這個引數, 觀察了下 對應於一個環境變數,如果想不截斷檔名,只要在程式執行之初加上:
 System.setProperty("mail.mime.splitlongparameters","false");
  就可以了。測試,解決。。。   另外由於發現了這個問題,google到了 java mail 的完整配置, 總結    郵件系統的不相容是導致這個錯誤的根本原因,還真不是編碼問題,所以有的時候看問題還不能那麼想當然。這個測試未必能測出,畢竟要滿足名字足夠長這個條件。在這裡分享這個問題,以免JAVA黨同學重複踩坑