2016-03-04 88 views
4

我試圖使用Delphi(D10S)將PDF文檔附加到電子郵件中,並且想要將名稱設置爲文件系統上文件的名稱以外的名稱。使用TIdMessageBuilderHtml設置電子郵件附件名

我發現下面的線(2011年),其中雷米勒博說,你可以通過設置TIdMessageBuilderAttachment對象的Name財產使用TIdMessageBuilderHtml它們附加到電子郵件時實現這一目標:

How to name attachment files constructed by TIdMessageBuilderHtml

但是,就像聽起來那麼簡單,它似乎並不適合我。電子郵件通過,但附件通過原始文件名稱,而不是我指定的。

以下是我希望按照我所描述的方式執行的一段代碼,但無論出於何種原因,它都不會。在這種情況下,我希望文件名爲desired_filename.pdf,但它通過undesired_filename.pdf。我已經刪除了郵件服務器憑證,原因很明顯:

procedure TForm4.Button1Click(Sender: TObject); 
var 
    FMessageBuilder : TIdMessageBuilderHtml; 
    FSMTP : TIdSMTP; 
    FMessage : TIdMessage; 
    FAttachment : TIdMessageBuilderAttachment; 
begin 
    FMessage := TIdMessage.Create(); 
    FMessageBuilder := TIdMessageBuilderHtml.Create; 
    FSMTP := TIdSMTP.Create; 

    FAttachment := FMessageBuilder.Attachments.Add('c:\undesired_filename.pdf'); 
    FAttachment.Name := 'desired_filename.pdf'; 
    FMessageBuilder.FillMessage(FMessage); 

    FMessage.Sender.Address := '<Insert Sender Address>'; 
    FMessage.Sender.Name := '<Insert Sender Name>'; 
    FMessage.From.Address := '<Insert From Address>'; 
    FMessage.From.Name := '<Insert From Name>'; 
    FMessage.Recipients.EMailAddresses := '<Insert Recepient Address>'; 
    FMessage.Subject := 'Attachment Test'; 

    FSMTP.Host := '<Insert Mail Host>'; 
    FSMTP.Username := '<Insert Username>'; 
    FSMTP.Password := '<Insert Password>'; 
    FSMTP.Connect; 
    FSMTP.Send(FMessage); 
    FSMTP.Disconnect; 
end; 

我已經在D10S和XE中測試了這一點,兩者都做同樣的事情。任何想法我做錯了什麼?

回答

3

TIdMessageBuilderAttachment既有FileNameName性能。將附件添加到構建器時,這些值將分配給TIdAttachment對象的相應屬性,該對象將被添加到TIdMessage.MessageParts集合中。

如果附件分配有Name,該值被放置在Content-Type報頭的name屬性,例如:

Content-Type: media/type; name="desired_filename.pdf" 

如果附件分配有FileName,該值被放置在filename屬性在Content-Disposition頭,例如:

Content-Disposition: attachment; filename="undesired_filename.pdf" 

如果兩個頭都存在,符合讀者將給予優先Content-Disposition時尋找文件名。這就是爲什麼你的讀者正在顯示不需要的文件名。

將物理文件添加到構建器時,TIdMessageBuilderAttachment當前不允許指定與真實文件不同的FileName。這是因爲TIdMessageBuilderAttachment不是實際加載文件的那個。它僅創建一個新的對象並將其FileName指定給該對象,因此它需要真實的文件名,否則附件在發送電子郵件時將無法加載。但是,TIdAttachmentFile確實允許在創建後自定義它自己的FileName。它有一個獨立的StoredPathName屬性來跟蹤物理文件,所以它的FileName可以是任何你想要的。

在@ fantaghirocco的例子,加入TStream給構建器導致TIdAttachmentMemory被添加到TIdMessage代替TIdAttachmentFile。由於不涉及物理文件,附件的FileName可以是任何你想要的。

因此,必須更新TIdMessageBuilderAttachment以允許設置與其StoredPathName分開的物理文件附件的FileName。在此期間,TIdMessage充滿後,您可以手動更新TIdAttachmentFile.FileName屬性,如:

FAttachment := FMessageBuilder.Attachments.Add('c:\undesired_filename.pdf'); 
FAttachment.Name := 'desired_filename.pdf'; 
FMessageBuilder.FillMessage(FMessage); 

for I := 0 to FMessage.MessageParts.Count-1 do 
begin 
    if FMessage.MessageParts[I].PartType = mptAttachment then 
    FMessage.MessageParts[I].FileName = FMessage.MessageParts[I].Name; 
end; 
+1

upvoted:從來沒有惹過這個傢伙! – fantaghirocco

+0

哇,我從來沒有想過你來回答這個問題!謝謝!如果在'TIdMessageBuilderAttachment'上設置'name'屬性只會更新'Content-Type'頭部,但'Content-Disposition'(填充我的'FileName')優先,那麼這是否意味着你在我鏈接的線程中給出的例子有同樣的問題,還是有一些微妙的差異,我錯過了?我只是假設他看起來很滿意你的答案。 –

+2

前面的例子會遭受同樣的問題。這是「TIdMessageBuilder」的一個限制,在我第一次寫入時我沒有考慮到,所以我將不得不對它進行更新以解決此問題,可能需要使用新屬性。 –

5

使用TIdMessageBuilderAttachments.Add超載它接受一個TStreamTIdMessageBuilderAttachment.FileName屬性設置爲所需的名稱是卓有成效的,我對XE4 10.6.0.4975。

stream := TFileStream.Create('c:\undesired_filename.pdf', fmOpenRead); 
FAttachment := FMessageBuilder.Attachments.Add(stream, 'application/pdf'); 
FAttachment.FileName := 'desired_filename.pdf'; 
+1

這樣的作品,謝謝! 但是,我仍然有點好奇,想知道我使用的方法有什麼問題。我會等待看看有沒有其他人能夠解決這個問題,然後再將其標記爲答案(我還沒有足夠的聲望來+1,但如果可以的話,我會這樣做)。 –

+1

@Adam歡迎您將此視爲解決方法,直到@Remy將解決您的問題 – fantaghirocco

+2

此方法的一個問題是,此重載導致輸入的「TStream」數據被複制到內存中(TIdAttachmentMemory對象是添加到'TIdMessage.MessageParts'集合中),因此這對於大型附件是不可取的。 –