使用Indy來發郵件坑不少啊,只不過有比沒有好吧,使用delphi6這種老工具沒辦法,只能使用了新一點的Indy版本9,公司限制。。。
這個問題是因為Indy代碼的bug導致的,也很奇怪這種Bug是因為沒有經過測試呢?還是測試沒有覆蓋到?
問題出在SendBody方法上,這個在之前一篇中提到過《技術筆記:Indy控件發送郵件》
當時是解決“發送Html”的問題才使用到了TIdText這個組件,因為基類TIdMessageClient中的SendBody方法中如果存在TIdText和TIdAttachment時有一個Bug:
if AMsg.MessageParts.TextPartCount > 1 then
必須>1這就有問題。因為只有一個TIdText所以這句話會導致無法發送body內容。所以解決方法是再添加一個相同的TIdText,之前測試還挺好的,但昨天發現反饋有人收到的郵件中有重復的body內容。也挺奇怪,我自己測試的時候沒有呢?而且試了不好郵箱都正常的。。
解決辦法比較簡單,就是繼承TIdSMTP,重寫SendBody方法。把這一句改一下:
if AMsg.MessageParts.TextPartCount >= 1 then
變成 >=吧,目前測試下來是正常的。至少在發郵件時不用再重復添加TIdText了。
另外提求新需求要求主題增加一些內容,以便收件人可以一眼看出郵件是啥意思。挺簡單的事情吧,結果發生了難過的事情。收到的郵件主題是截斷的,而且後面的內容解析錯誤。心想這是個什麼鬼。網上一找有同樣的問題,原因也找到了:
【原因】Indy的IdMessage組件在生成待發送的郵件時,主題中有漢字時會按RFC2045~2047的base64編碼規范對主題進行編碼,base64要求編碼後每行長度不能超過75(76)個字節;所以當主題過長時要分行。問題是IdMessage編碼時,用了2對分行符<CR><LF><CR><LF>,而RFC規定<CR><LF><CR><LF>表示郵件中一節的結束,所以接收郵件的程序只會對第1行解碼,其余的理解為郵件內容了。
可見Indy確實主要照顧了英文的使用,像中文這種復雜的點語言估計都沒好好測試吧,另外以前只聽說Indy問題多但一直沒感覺到,現在接觸多一些果然有所體會啊。當然高人也給出了解決方案,就是把這個<CR><LF><CR><LF>換成<CR><LF>這樣就行了。
procedure TIdSmtpEx.SendHeader(AMsg: TIdMessage); var LHeaders: TIdHeaderList; begin LHeaders := AMsg.GenerateHeader; try //解決標題過長時導致的收件方解碼錯誤問題 LHeaders.Text := StringReplace(LHeaders.Text, #13#10#13#10, #13#10, [rfReplaceAll]); WriteStrings(LHeaders); finally FreeAndNil(LHeaders); end; end;
#13#10就是回車和換行的意思,對應<CR><LF>
測試下來發現是正確的。
代碼已經放到gitbub上:https://github.com/mini188/IndyMail