TIdMessage - 附件在Body中显示为Base64

Jer*_*dge 0 html delphi smtp indy email-attachments

我正在使用Indy组件(TIdMessage)通过SMTP发送电子邮件.这样的电子邮件需要是HTML,并且需要携带附件.

现在,如果我以纯文本(ContentType := 'text/plain')发送电子邮件并附加文件,则电子邮件发送得很好,附件找到了所有内容.

但是,一旦我改变ContentTypetext/html,我有一个非常奇怪的结果.电子邮件的整个主体被显然替换为底层电子邮件数据(用我的话说),并将正文中的附件显示为Base64数据.

例如,这里只是这样一个结果电子邮件的前几行:

This is a multi-part message in MIME format

--YGuFowdSjNaa=_khosBzZl5L8uGVtfasBX
Content-Type: text/plain; charset="us-ascii"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

This is the body of a test email.
--YGuFowdSjNaa=_khosBzZl5L8uGVtfasBX
Content-Type: application/octet-stream; name="TagLogo.jpg"
Content-Transfer-Encoding: base64
Content-Disposition: inline; filename="TagLogo.jpg"

/9j/4AAQSkZJRgABAQEASwBLAAD/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcU
FhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgo
KCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCADhAG8DASIA
AhEBAxEB/8QAHAAAAgMBAQEBAAAAAAAAAAAAAAcFBggEAgED/8QAPxAAAQIFAwEEBwYFAwQDAAAA
AQIDAAQFBhEHEiExCBNBdSI3OFFhsrMUMkJxgZEVIzNSgmJyoRaSosEk0eH/xAAWAQEBAQAA

虽然原来的身体只是

This is the body of a test email.
Run Code Online (Sandbox Code Playgroud)

代码非常简单,匹配我在网上找到的所有例子......

IdMessage.Charset := 'UTF-8';
IdMessage.ContentType := 'text/html'; // <-- text/plain works fine.....
IdMessage.Body := 'This is the body of a test email.';

... (Assigning Other Unrelated Properties) ...

A := TIdAttachmentFile.Create(IdMessage.MessageParts, 'C:\SomeFile.jpg'); // <-- Originally the only LOC here
A.ContentTransfer := 'base64'; // <-- Tried with and without
A.ContentType := 'application/octet-stream'; // <-- Tried with and without
//A.ContentType := 'image/jpeg'; // <-- Tried with and without
A.ContentDisposition := 'inline'; // <-- Tried with and without
Run Code Online (Sandbox Code Playgroud)

为什么这会导致"垃圾"电子邮件,如何在支持带附件的HTML电子邮件正文时解决它?

PS - 如果它有任何区别,附件将是最终在电子邮件正文中在线使用的图像.

Rem*_*eau 8

这样的电子邮件需要是HTML,并且需要携带附件

我在Indy的网站上有关于这个主题的博客文章,我建议你阅读它们:

HTML消息

新的HTML Message Builder类

为什么这会导致"垃圾"电子邮件

简而言之,因为你没有TIdMessage正确填充.

在您的特定示例中,您将HTML放入TIdMessage.Body属性中,但您还要将一个项添加到TIdMessage.MessageParts集合中.该组合内部有一些特殊处理TIdMessageClient(TIdSMTP源自).特别是,当:

  • TIdMessage是MIME编码的,
  • 并且TIdMessage.IsMsgSinglePartMime是假的,
  • TIdMessage.IsBodyEmpty()返回false(TIdMessage.Body包含非空白文本时),
  • 并且TIdMessage.ConvertPreamble是真的(默认情况下是这样),
  • 并且该TIdMessage.MessageParts集合不为空,并且没有TIdText对象.

然后TIdMessageClient.SendBody()将HTML移动到集合中的新TIdText对象MessageParts,并生成MIME编码的电子邮件正文,其中TIdMessage.Body文本作为第一个MIME部分.假设在这种组合中,用户将消息明文放在TIdMessage.Body意外中,因此Indy将其移动到需要进一步处理的位置,而不更改电子邮件中的任何其他内容.但是,这意味着TIdMessage.ContentType不调整属性(可能是应该查看的错误).在你的情况,你都设置ContentTypetext/html当它真正需要是一个MIME multipart/...类型,而不是(根据附件到HTML的关系).

所以,您实际上是在发送这样的电子邮件:

Content-Type: text/html; charset=us-ascii; boundary="AduWRpEOzrMvJDhg6Jp8EsEFw5Qr1p=_1v"
MIME-Version: 1.0
Date: Tue, 8 Aug 2017 12:58:00 -0700

This is a multi-part message in MIME format

--AduWRpEOzrMvJDhg6Jp8EsEFw5Qr1p=_1v
Content-Type: text/plain; charset="us-ascii"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

This is the body of a test email.

--AduWRpEOzrMvJDhg6Jp8EsEFw5Qr1p=_1v
Content-Type: application/octet-stream;
    name="SomeFile.jpg"
Content-Transfer-Encoding: base64
Content-Disposition: inline;
    filename="SomeFile.jpg"

<base64 data here>

--AduWRpEOzrMvJDhg6Jp8EsEFw5Qr1p=_1v--

这告诉收件人电子邮件,当它真的不是时,整个电子邮件都是HTML.它实际上是多种MIME类型的混合.由于您希望图像位于HTML内部,因此Content-Type需要使用顶级标题multipart/related(我在博客文章中详细介绍了解释原因).

如何在支持带附件的HTML电子邮件正文的同时解决它?

如果它有任何区别,附件将是最终在电子邮件正文中在线使用的图像.

在处理时TIdMessage,最好是:

  • 仅填充TIdMessage.Body自身,并忽略该TIdMessage.MessageParts集合.

  • 将所有内容放入TIdMessage.MessageParts集合,文本和所有内容中,并忽略该TIdMessage.Body属性.

在这种情况下,由于您需要附件,因此您需要使用该MessageParts集合,因此您可以:

  1. 自己将HTML放在集合中的TIdText对象中TIdMessage.MessageParts(不要让它TIdMessageClient为你做),然后设置TIdMessage.ContentTypemultipart/related:

    IdMessage.ContentType := 'multipart/related; type="text/html"';
    ... (Assigning Other Unrelated Properties) ...
    
    T := TIdText.Create(IdMessage.MessageParts, nil);
    T.ContentType := 'text/html';
    T.Charset := 'utf-8';
    T.Body.Text := '<html><body>This is the body of a test email.<p><img src="cid:myimage"></body></html>';
    
    A := TIdAttachmentFile.Create(IdMessage.MessageParts, 'C:\SomeFile.jpg');
    A.ContentTransfer := 'base64';
    A.ContentType := 'image/jpeg';
    A.ContentDisposition := 'inline';
    A.ContentID := 'myimage';
    
    Run Code Online (Sandbox Code Playgroud)

    或者,如果要为非HTML阅读器提供纯文本消息,则需要将HTML和纯文本(按此顺序)包装在内部multipart/alternative,同时保持HTML和图像附件内multipart/related:

    IdMessage.ContentType := 'multipart/alternative';
    ... (Assigning Other Unrelated Properties) ...
    
    T := TIdText.Create(IdMessage.MessageParts, nil);
    T.ContentType := 'multipart/related; type="text/html"';
    
    T := TIdText.Create(IdMessage.MessageParts, nil);
    T.ContentType := 'text/html';
    T.Charset := 'utf-8';
    T.Body.Text := '<html><body>This is the body of a test email.<p><img src="cid:myimage"></body></html>';
    T.ParentPart := 0;
    
    A := TIdAttachmentFile.Create(IdMessage.MessageParts, 'C:\SomeFile.jpg');
    A.ContentTransfer := 'base64';
    A.ContentType := 'image/jpeg';
    A.ContentDisposition := 'inline';
    A.ContentID := 'myimage';
    A.ParentPart := 0;
    
    T := TIdText.Create(IdMessage.MessageParts, nil);
    T.ContentType := 'text/plain';
    T.Charset := 'utf-8';
    T.Body.Text := 'This is the body of a test email.';
    
    Run Code Online (Sandbox Code Playgroud)
  2. 使用TIdMessageBuilderHtml该类,让它TIdMessage为您配置内容:

    uses
      ..., IdMessageBuilder;
    
    MB := TIdMessageBuilderHtml.Create;
    try
      // optional...
      MB.PlainText.Text := 'This is the body of a test email.';
      MB.PlainTextCharSet := 'utf-8';
    
      MB.Html.Text := '<html><body>This is the body of a test email.<p><img src="cid:myimage"></body></html>';
      MB.HtmlCharSet := 'utf-8';
      MB.HtmlFiles.Add('C:\SomeFile.jpg', 'myimage');
    
      MB.FillMessage(IdMessage);
    finally
      MB.Free;
    end;
    
    ... (Assigning Other Unrelated Properties) ...
    
    Run Code Online (Sandbox Code Playgroud)