如何通过Indy正确发送含Base64嵌入式图片的HTML邮件?
问题描述
我希望用Indy发送带有嵌入式图片的邮件,HTML模板里包含Base64格式的图片。测试用HTML模板如下:
<html> <head> </head> <body> <div> <p>Some text</p> <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4 //8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==" alt="Red dot" /> </div> </body> </html>
这个HTML在Chrome、Firefox等浏览器里能正常加载图片,但通过Indy发送邮件后,图片无法正确显示,要么收到纯HTML代码,要么图片破损或空白。我尝试了以下代码:
uses idMessage, idText, IdSMTP, IdSSLOpenSSL, IdExplicitTLSClientServerBase; procedure SendMail; var html: TStringList; email: TIdMessage; idSMTP: TIdSMTP; idSSL: TIdSSLIOHandlerSocketOpenSSL; begin html:= TStringlist.Create; html.LoadFromFile('<my_html_file>'); email := TIdMessage.Create(nil); email.From.Text := 'from@mail.com'; email.From.Name:= 'from name'; /// email.Recipients.EMailAddresses := 'recipient'; email.Subject := 'From DELPHI'; email.ContentType := 'multipart/mixed'; //email comes with HTML text //email.ContentType := 'text/html'; //email comes with plain text, but not images email.Body.Assign(html); // SSL stuff // idSSL:= TIdSSLIOHandlerSocketOpenSSL.Create(nil); idSSL.SSLOptions.Mode:= sslmClient; idSSL.SSLOptions.Method:= sslvSSLv23; // SMTP stuff // idSMTP:= TIdSMTP.Create(nil); idSMTP.IOHandler:= idSSL; idSMTP.Host:= 'smtp.office365.com'; idSMTP.Port:= 587; idSMTP.AuthType := satDefault; //idSMTP.UseTLS:= utUseImplicitTLS; idSMTP.UseTLS:= utUseExplicitTLS; idSMTP.Username:= 'mail@mail.com'; idSMTP.Password:= 'pass'; try idSMTP.Connect(); idSMTP.Send(email); ShowMessage('Sent'); except on E: Exception do ShowMessage('Failed: ' + E.Message); end; end;
同时我也试过使用TIdMessageBuilderHtml,但都没成功。请问我哪里操作有误?
解决方法
你的问题主要出在两个核心点:
- 邮件客户端对
data URI支持有限:虽然浏览器能解析Base64内嵌的data URI,但很多邮件客户端(比如Outlook、部分Web邮箱)并不支持这种方式显示图片,这是图片空白/破损的主要原因之一。 - Indy邮件构建不符合MIME规范:直接设置
ContentType并赋值Body的方式错误,正确的内嵌图片邮件应该采用CID(Content-ID)引用内嵌附件的标准方式。
正确实现步骤
- 修改HTML模板,将图片的
src从data URI改为cid:唯一标识,比如:
<html> <head> </head> <body> <div> <p>Some text</p> <img src="cid:red_dot" alt="Red dot" /> </div> </body> </html>
- 使用
TIdMessageBuilderHtml构建邮件,将图片作为LinkedResource添加,并绑定对应的CID。 - 依赖
TIdMessageBuilderHtml自动处理多部分邮件的MIME结构。
修正后的代码
uses idMessage, idText, IdSMTP, IdSSLOpenSSL, IdExplicitTLSClientServerBase, IdMessageBuilderHtml, IdAttachmentFile, IdGlobal; procedure SendMail; var html: TStringList; email: TIdMessage; idSMTP: TIdSMTP; idSSL: TIdSSLIOHandlerSocketOpenSSL; builder: TIdMessageBuilderHtml; begin html := TStringList.Create; try html.LoadFromFile('<my_html_file>'); // 替换为修改后的HTML文件路径 email := TIdMessage.Create(nil); try email.From.Text := 'from@mail.com'; email.From.Name := 'from name'; email.Recipients.EMailAddresses := 'recipient'; email.Subject := 'From DELPHI'; // 用TIdMessageBuilderHtml构建带内嵌图片的HTML邮件 builder := TIdMessageBuilderHtml.Create; try builder.Html.Assign(html); // 添加内嵌图片,设置Content-ID为"red_dot",对应HTML里的cid:red_dot builder.HtmlFiles.Add('<你的PNG图片文件路径>', 'red_dot'); // 将构建好的内容赋值给邮件 builder.FillMessage(email); finally builder.Free; end; // SSL配置 idSSL := TIdSSLIOHandlerSocketOpenSSL.Create(nil); try idSSL.SSLOptions.Mode := sslmClient; idSSL.SSLOptions.Method := sslvSSLv23; // SMTP配置 idSMTP := TIdSMTP.Create(nil); try idSMTP.IOHandler := idSSL; idSMTP.Host := 'smtp.office365.com'; idSMTP.Port := 587; idSMTP.AuthType := satDefault; idSMTP.UseTLS := utUseExplicitTLS; idSMTP.Username := 'mail@mail.com'; idSMTP.Password := 'pass'; idSMTP.Connect; try idSMTP.Send(email); ShowMessage('Sent'); finally idSMTP.Disconnect; end; finally idSMTP.Free; end; finally idSSL.Free; end; finally email.Free; end; finally html.Free; end; end;
关键说明
TIdMessageBuilderHtml.HtmlFiles.Add()会自动将图片转为内嵌附件,设置正确的Content-ID和Content-Disposition: inline,确保邮件客户端能通过CID引用加载图片。- 若坚持使用Base64 data URI,需设置
email.ContentType := 'text/html'并指定字符编码(如email.CharSet := 'UTF-8'),但仍无法保证所有邮件客户端兼容,因此优先推荐CID内嵌附件方案。
内容的提问来源于stack exchange,提问作者snowdev
相关产品推荐
相关产品推荐

