我正在尝试使用 Delphi (D10S) 将 PDF 文档附加到电子邮件,并且我想将名称设置为文件系统上文件名称以外的名称。
我发现了以下线程(2011 年),其中 Remy Lebeau 指出,当使用
Name
将对象附加到电子邮件时,可以通过设置 TIdMessageBuilderAttachment
对象的 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 中测试了这一点,两者的效果相同。有什么想法我做错了吗?
使用接受
TIdMessageBuilderAttachments.Add
的 TStream
重载并将 TIdMessageBuilderAttachment.FileName
属性设置为所需的名称,对我来说在 XE4、Indy 10.6.0.4975.
stream := TFileStream.Create('c:\undesired_filename.pdf', fmOpenRead);
FAttachment := FMessageBuilder.Attachments.Add(stream, 'application/pdf');
FAttachment.FileName := 'desired_filename.pdf';
TIdMessageBuilderAttachment
具有 FileName
和 Name
属性。将附件添加到构建器时,这些值将分配给添加到 TIdAttachment
集合中的 TIdMessage.MessageParts
对象的相应属性。
如果附件分配了
Name
,则该值将放置在 name
标头的 Content-Type
属性中,例如:
Content-Type: media/type; name="desired_filename.pdf"
如果附件分配了
FileName
,则该值将放置在 filename
标头的 Content-Disposition
属性中,例如:
Content-Disposition: attachment; filename="undesired_filename.pdf"
如果两个标头都存在,则符合要求的读者在查找文件名时将优先考虑
Content-Disposition
。这就是为什么您的阅读器显示不需要的文件名。
将物理文件添加到构建器时,
TIdMessageBuilderAttachment
目前不允许您指定与真实文件不同的 FileName
。这是因为 TIdMessageBuilderAttachment
不是实际加载文件的。它只是创建一个新的 TIdAttachmentFile
对象并将其 FileName
分配给该对象,因此它需要真实的文件名,否则发送电子邮件时附件将无法加载。但是,TIdAttachmentFile
确实允许在创建后自定义其自己的 FileName
。它有一个单独的 StoredPathName
属性来跟踪物理文件,因此它的 FileName
可以是您想要的任何内容。
在 @fantaghirocco 的示例中,向构建器添加
TStream
会导致将 TIdAttachmentMemory
添加到 TIdMessage
而不是 TIdAttachmentFile
。由于不涉及物理文件,附件的 FileName
可以是您想要的任何内容。
因此,必须更新
TIdMessageBuilderAttachment
,以允许将物理文件附件的 FileName
与其 StoredPathName
分开设置。同时,您可以在 TIdAttachmentFile.FileName
填充后手动更新 TIdMessage
属性,例如:
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;
更新:
首次发布此答案后,通过在
WantedFileName
类中添加新的 TIdMessageBuilderAttachment
属性解决了该问题。
您可以将
WantedFileName
设置为您想要的任何值,填充 FileName
时,它将被分配给附件的 TIdMessage
属性。如果 WantedFileName
为空,则将像以前一样使用 TIdMessageBuilderAttachment.FileName
属性。
此外,如果
WantedFileName
属性也为空,则将使用 TIdMessageBuilderAttachment.Name
。因此,您现在可以在一处设置所需的名称,如果需要,它将用于 Content-Type
和 Content-Disposition
标头,例如:
FAttachment := FMessageBuilder.Attachments.Add('c:\undesired_filename.pdf');
FAttachment.WantedFileName := 'desired_filename.pdf';
FMessageBuilder.FillMessage(FMessage);
填写
TIdAttachment.FileName
后不再需要手动更新 TIdMessage
属性。