TIdMessage - 附件以Base64形式显示在主体中

问题描述:

我正在使用Indy组件(TIdMessage)通过SMTP发送电子邮件。这样的电子邮件需要HTML,并需要携带附件。TIdMessage - 附件以Base64形式显示在主体中

现在,如果我以纯文本形式发送电子邮件(ContentType := 'text/plain'),并附加一个文件,电子邮件发送很好,附件找到和一切。

但是,一旦我将ContentType更改为text/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. 

的代码很简单,匹配所有的例子我可以在网上找到...

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 

为什么这会导致一个“垃圾”电子邮件,以及如何做我解决它,同时支持带附件的HTML电子邮件正文?

PS - 如果有任何区别,附件将是最后在电子邮件正文中内嵌使用的图像。

这样的电子邮件必须是HTML,并且需要进行附件

我对这个在印第安纳波利斯的网站博客文章很有话题,我建议你阅读:

HTML Messages

New HTML Message Builder class

为什么然而这是esulting在“垃圾”邮件

简单地说,是因为你没有正确填充TIdMessage

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

  • TIdMessage被MIME编码的,
  • TIdMessage.IsMsgSinglePartMime为假,
  • TIdMessage.IsBodyEmpty()假(当TIdMessage.Body包含非空白文本),
  • TIdMessage.ConvertPreamble是真的(默认情况下),
  • TIdMessage.MessageParts集合不是空的,也没有TIdText对象。

然后TIdMessageClient.SendBody()将HTML移到MessageParts收集在一个新的TIdText对象,并生成一个MIME编码的电子邮件正文与TIdMessage.Body文本作为第一个MIME部分。假定在这种组合中,用户已经意外地将消息明文放在TIdMessage.Body中,所以Indy将它移动到需要进一步处理的位置,而不改变电子邮件中的其他任何内容。但是,这意味着TIdMessage.ContentType属性未被调整(可能是应该查看的错误)。在你的情况下,你需要将ContentType设置为text/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'; 
    

    或者,如果要为非HTML阅读器提供纯文本邮件,则需要将multipart/alternative中的HTML和纯文本(按此顺序)封装起来,同时将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.'; 
    
  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) ... 
    
+0

我想我只是假设,因为每个附件都有自己的内容类型,它会立即知道差异,但是这种假设是错误的。 –

+0

@JerryDodge:在某种程度上,它确实如此。但是,在电子邮件生成过程中还有很多事情发生,而且OP实际上正在通过一些特殊处理打到角落。我更新了我的答案,以解释发生了什么。 –

内容类型应为multipart/mixed

+0

只是尝试,并且在附件去细,身体不是HTML(没有什么不同来自'text/plain')。该部分非常重要... –

+0

实际上,对于HTML内嵌的图像,HTML和附件需要包含在'multipart/related; type =“text/html”',并且需要额外的设置才能将附件实际链接到HTML。 –