使用 TIdMessageBuilderHtml 设置电子邮件附件名称

Setting email attachment name using TIdMessageBuilderHtml

我正在尝试使用 Delphi (D10S) 将 PDF 文档附加到电子邮件中,我想将名称设置为文件系统上文件名称以外的名称。

我发现了以下主题(自 2011 年起),其中 Remy Lebeau 指出您可以通过在将 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 中测试过,两者都是一样的。知道我做错了什么吗?

使用接受 TStreamTIdMessageBuilderAttachments.Add 重载并将 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 具有 FileNameName 属性。将附件添加到构建器时,这些值将分配给添加到 TIdMessage.MessageParts collection.

TIdAttachment object 的相应属性

如果附件分配了 Name,值将放在 Content-Type header 的 name 属性中,例如:

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

如果附件分配了 FileName,值将放在 Content-Disposition header 的 filename 属性中,例如:

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

如果两个 header 都存在,则在查找文件名时符合 reader 的将给予 Content-Disposition 优先权。这就是为什么您的 reader 显示不需要的文件名。

将物理文件添加到构建器时,TIdMessageBuilderAttachment 目前不允许您指定与实际文件不同的 FileName。这是因为 TIdMessageBuilderAttachment 不是实际加载文件的那个。它只是创建一个新的 TIdAttachmentFile object 并将其 FileName 分配给那个 object,因此它需要真实的文件名,否则在发送电子邮件时附件将无法加载。但是,TIdAttachmentFile 允许在创建后自定义其自身的 FileName。它有一个单独的 StoredPathName 属性 来跟踪物理文件,因此它的 FileName 可以是任何你想要的。

在@fantaghirocco 的示例中,将 TStream 添加到构建器会导致将 TIdAttachmentMemory 添加到 TIdMessage 而不是 TIdAttachmentFile。由于不涉及物理文件,附件的 FileName 可以是您想要的任何内容。

因此,必须更新 TIdMessageBuilderAttachment 以允许将物理文件附件的 FileName 与其 StoredPathName 分开。同时,可以在TIdMessage填满后手动更新TIdAttachmentFile.FileName属性,eg:

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;