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,并且需要进行附件
我对这个在印第安纳波利斯的网站博客文章很有话题,我建议你阅读:
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
集合,因此您可以:
-
把HTML的
TIdText
对象TIdMessage.MessageParts
收集自己内(唐“别让TIdMessageClient
为你做它),然后设置TIdMessage.ContentType
到multipart/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.';
-
使用
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) ...
内容类型应为multipart/mixed。
只是尝试,并且在附件去细,身体不是HTML(没有什么不同来自'text/plain')。该部分非常重要... –
实际上,对于HTML内嵌的图像,HTML和附件需要包含在'multipart/related; type =“text/html”',并且需要额外的设置才能将附件实际链接到HTML。 –
我想我只是假设,因为每个附件都有自己的内容类型,它会立即知道差异,但是这种假设是错误的。 –
@JerryDodge:在某种程度上,它确实如此。但是,在电子邮件生成过程中还有很多事情发生,而且OP实际上正在通过一些特殊处理打到角落。我更新了我的答案,以解释发生了什么。 –