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

q9rjltbz  于 2023-10-18  发布在  其他
关注(0)|答案(2)|浏览(201)

我正尝试使用 Delphi (D10 S)将PDF文档附加到电子邮件中,我想将名称设置为文件系统上文件名以外的名称。
我发现了以下线程(从2011年开始),其中雷米勒博表示,您可以通过在使用TIdMessageBuilderHtmlTIdMessageBuilderAttachment对象附加到电子邮件时设置TIdMessageBuilderAttachment对象的Name属性来实现这一点:
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中测试过了,两者都是如此。知道我哪里做错了吗

rqmkfv5c

rqmkfv5c1#

TIdMessageBuilderAttachment同时具有FileNameName属性。当向构建器添加附件时,这些值被分配给TIdMessage.MessageParts集合中添加的TIdAttachment对象的相应属性。
如果附件分配了Name,则该值将放置在Content-Type头的name属性中,例如:

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

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

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

如果两个头都存在,则符合条件的读取器在查找文件名时将给予给予Content-Disposition优先级。这就是为什么你的阅读器显示不需要的文件名。
向构建器添加物理文件时,TIdMessageBuilderAttachment当前不允许您指定与真实的文件不同的FileName。这是因为TIdMessageBuilderAttachment并不是真正加载文件的那个。它只是创建一个新的TIdAttachmentFile对象,并将其FileName分配给该对象,因此它需要真实的文件名,否则发送电子邮件时附件将无法加载。但是,TIdAttachmentFile允许在创建后自定义自己的FileName。它有一个单独的StoredPathName属性来跟踪物理文件,所以它的FileName可以是任何你想要的。
在@ fashion hirocco的示例中,将TStream添加到构建器会导致TIdAttachmentMemory被添加到TIdMessage,而不是TIdAttachmentFile。由于不涉及物理文件,附件的FileName可以是您想要的任何文件。
因此,TIdMessageBuilderAttachment必须进行更新,以允许将物理文件附件的FileName与其StoredPathName分开设置。同时,您可以在填充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;

更新:

在这个答案第一次发布之后,这个问题已经通过在TIdMessageBuilderAttachment类中添加一个新的WantedFileName属性来解决。
您可以将WantedFileName设置为任何您想要的值,在填充TIdMessage时,它将被分配给附件的FileName属性。如果WantedFileName为空,则将使用TIdMessageBuilderAttachment.FileName属性代替,如前所述。
此外,如果TIdMessageBuilderAttachment.Name属性也为空,则将使用WantedFileName。因此,您现在可以在一个地方设置所需的名称,如果需要,它将用于Content-TypeContent-Disposition头部,例如:

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

在填充TIdMessage后,不再需要手动更新TIdAttachment.FileName属性。

j0pj023g

j0pj023g2#

使用TIdMessageBuilderAttachments.Add重载(它接受TStream)并将TIdMessageBuilderAttachment.FileName属性设置为所需的名称,这对我在 XE4Indy 10.6.0.4975上很有用。

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

相关问题