我正在使用Indy组件(TIdMessage
)通过SMTP发送电子邮件。这样的电子邮件需要是HTML,并且需要携带附件。
现在,如果我以纯文本(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
为什么会导致&#34;垃圾&#34;电子邮件,如何在支持带附件的HTML电子邮件正文时解决它?
PS - 如果它有所不同,附件将是最终在电子邮件正文中在线使用的图像。
答案 0 :(得分:8)
这样的电子邮件需要是HTML,并且需要携带附件
我在Indy的网站上有关于这个主题的博客文章,我建议你阅读它们:
New HTML Message Builder class
为什么会导致&#34;垃圾&#34;电子邮件
简而言之,因为您没有正确填充TIdMessage
。
在您的特定示例中,您将HTML放入TIdMessage.Body
属性,但您还要向TIdMessage.MessageParts
集合中添加项目。该组合在TIdMessageClient
(TIdSMTP
派生自)内部有一些特殊处理。尤其是:
TIdMessage
将采用MIME编码,TIdMessage.IsMsgSinglePartMime
为false,TIdMessage.IsBodyEmpty()
返回false(当TIdMessage.Body
包含非空白文本时),TIdMessage.ConvertPreamble
为真(默认情况下),TIdMessage.MessageParts
集合不为空,并且其中没有TIdText
个对象。然后TIdMessageClient.SendBody()
会将HTML移动到TIdText
集合中的新MessageParts
对象,并生成一个MIME编码的电子邮件正文,其中TIdMessage.Body
文本为第一个MIME部分。假设在这种组合中,用户已将消息明文放在TIdMessage.Body
中,因此Indy会将其移动到需要进一步处理的位置,而不会更改电子邮件中的任何其他内容。但是,这意味着TIdMessage.ContentType
属性未调整(可能是应该查看的错误)。在您的情况下,当ContentType
确实需要为MIME text/html
类型时(取决于附件与HTML的关系),您将multipart/...
设置为Content-Type
。
所以,您实际上是在发送这样的电子邮件:
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中,因此顶级multipart/related
标题需要为TIdMessage
(我在博客文章中详细介绍了解其原因)。
如何在支持带附件的HTML电子邮件正文时解决此问题?
如果它有任何区别,附件将是最终在电子邮件正文中在线使用的图像。
在处理TIdMessage.Body
时,最好是:
仅填充TIdMessage.MessageParts
,并忽略TIdMessage.MessageParts
集合。
将所有内容放入TIdMessage.Body
集合,文本和所有内容中,并忽略MessageParts
属性。
在这种情况下,由于您需要附件,因此您需要使用TIdText
集合,因此您可以:
将HTML放在TIdMessage.MessageParts
集合中的TIdMessageClient
对象中(不要让TIdMessage.ContentType
为您执行此操作),然后设置{{ 1}}到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) ...
答案 1 :(得分:-3)
内容类型应为multipart/mixed。