在 HTML 电子邮件中嵌入图像

embedding image in html email

提问人:tbone 提问时间:7/15/2011 最后编辑:tbone 更新时间:5/27/2023 访问量:561594

问:

我正在尝试发送一封包含嵌入式 gif 图像的多部分/相关 html 电子邮件。此电子邮件是使用 Oracle PL/SQL 生成的。我的尝试失败了,图像显示为红色 X(在 Outlook 2007 和 yahoo 邮件中)

我已经发送 html 电子邮件一段时间了,但我现在的要求是在电子邮件中使用多个 gif 图像。我可以将它们存储在我们的一个 Web 服务器上并链接到它们,但许多用户的电子邮件客户端不会自动显示它们,并且需要更改设置或手动下载每封电子邮件。

所以,我的想法是嵌入图像。我的问题是:

  1. 我在这里做错了什么?
  2. 嵌入方法是否正确?
  3. 如果我需要使用越来越多的图像,还有其他选择吗?附件不起作用,因为图像通常是徽标和图标,在消息的上下文中没有意义。此外,电子邮件的某些元素是指向在线系统的链接,因此生成静态 PDF 并附加不起作用(据我所知)。

片段:

MIME-Version: 1.0
To: [email protected]
BCC: [email protected]
From: [email protected]
Subject: Test
Reply-To: [email protected]
Content-Type: multipart/related; boundary="a1b2c3d4e3f2g1"

--a1b2c3d4e3f2g1

content-type: text/html;

    <html>
    <head><title>My title</title></head>
    <body>
    <div style="font-size:11pt;font-family:Calibri;">
    <p><IMG SRC="cid:my_logo" alt="Logo"></p>

... more html here ...

</div></body></html> 

--a1b2c3d4e3f2g1

Content-Type: image/gif;
Content-ID:<my_logo>
Content-Transfer-Encoding: base64
Content-Disposition: inline

[base64 image data here]

--a1b2c3d4e3f2g1--

非常感谢。

顺便说一句:是的,我已经验证了 base64 数据是正确的,因为我可以将图像嵌入到 html 本身中(使用与创建标头数据相同的算法)并在 Firefox/IE 中查看图像。

我还应该注意,这不是垃圾邮件,电子邮件会发送给每天期待它的特定客户。内容是数据驱动的,而不是广告。

HTML 图像 Oracle 电子邮件 MIME

评论

0赞 JonLim 7/16/2011
快速提问:您是将这些图像托管到异地还是直接嵌入到电子邮件中?
0赞 tbone 7/16/2011
我问题的一部分真的,我都可以做。我试图在这里嵌入它们,但没有成功。如果我只是链接到它们,许多用户如果不先下载它们,就不会看到这些图像,我想避免这种情况。
1赞 JonLim 7/16/2011
一个常客为我工作,但这是我在场外托管的图像。这对你不起作用?<img src="URL" />
0赞 tbone 7/16/2011
“作品”是主观的......是的,如果用户每次都愿意下载图像,它就会起作用,但我想避免这种情况并嵌入图像。
1赞 tbone 7/16/2011
@JonLim:感谢您的调查,请参阅我在答案中的评论,了解我遗漏的内容。

答:

178赞 Bernd 7/16/2011 #1

尝试直接插入它,这样您就可以在电子邮件的不同位置插入多张图像。

<img src="data:image/jpg;base64,{{base64-data-string here}}" />

并使这篇文章对其他人有用: 如果您没有 base64 数据字符串,请在以下位置轻松创建一个:从图像文件 http://www.motobit.com/util/base64-decoder-encoder.asp

电子邮件源代码看起来像这样,但我真的不能告诉你这个边界的东西是做什么用的:

 To: [email protected]
 Subject: ...
 Content-Type: multipart/related;
 boundary="------------090303020209010600070908"

This is a multi-part message in MIME format.
--------------090303020209010600070908
Content-Type: text/html; charset=ISO-8859-15
Content-Transfer-Encoding: 7bit

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>

    <meta http-equiv="content-type" content="text/html; charset=ISO-8859-15">
  </head>
  <body bgcolor="#ffffff" text="#000000">
    <img src="cid:part1.06090408.01060107" alt="">
  </body>
</html>

--------------090303020209010600070908
Content-Type: image/png;
 name="moz-screenshot.png"
Content-Transfer-Encoding: base64
Content-ID: <part1.06090408.01060107>
Content-Disposition: inline;
 filename="moz-screenshot.png"

[base64 image data here]

--------------090303020209010600070908--

编辑:哦,我刚刚意识到,如果你插入我帖子中的第一个代码片段来用 thunderbird 写一封电子邮件,thunderbird 会自动更改 html 代码,使其看起来与我帖子中的第二个代码几乎相同。

评论

5赞 tbone 7/16/2011
先试了一下,它对我的电子邮件不起作用。可以在 IE/Firefox 中查看,但不能作为电子邮件发送。
0赞 tbone 7/16/2011
也许你知道一种方法(内容类型是什么?文本/html?我需要知道的电子邮件标题,以这种方式发送混合的html/图像文件)
1赞 tbone 3/9/2012
@Zesty使用 @[username] 提醒某人,刚刚看到了您的问题。我使用utl_smtp。对我来说,我必须使用 html 正文、边界等创建一个 clob,然后通过 utl_smtp 发送。有关简单示例,请参阅此处: oracle-base.com/articles/misc/EmailFromOraclePLSQL.php 请注意,此链接不显示嵌入式图像方法,但提供了详细信息,可帮助您继续。
67赞 Michael Böckling 10/28/2014
许多主流客户端不支持电子邮件中的数据 URI,不应使用,请参阅:campaignmonitor.com/blog/post/3927/...
2赞 hsb1007 4/27/2015
它似乎在 hotmail / icloud =( 我错过了什么吗
11赞 Erwin Mayer 3/14/2013 #2

如果它不起作用,您可以尝试以下工具之一,将图像转换为 HTML 表格(但要注意图像的大小):

评论

18赞 Kristjan Liiva 7/28/2017
img2hmtl 是我一段时间以来见过的最古怪的解决方案/想法。+1
1赞 Red Pill 2/24/2023
...其中术语“古怪”总结了 img2html 的这一特性: 作为解决方案,我们编写了一个应用程序,将图像的每个像素转换为相应的 HTML 单元格。
16赞 Pavel Perna 1/8/2014 #3

我发现这里的任何答案都没有用,所以我提供了我的解决方案。

  1. 问题是您使用的是内容类型,在这种情况下不好。我正在使用它并在其中(它适用于大多数客户端)。multipart/relatedmultipart/mixedmultipart/alternative

  2. 消息结构应如下所示:

    [Headers]
    Content-type:multipart/mixed; boundary="boundary1"
    --boundary1
    Content-type:multipart/alternative; boundary="boundary2"
    --boundary2
    Content-Type: text/html; charset=ISO-8859-15
    Content-Transfer-Encoding: 7bit
    [HTML code with a href="cid:..."]
    
    --boundary2
    Content-Type: image/png;
    name="moz-screenshot.png"
    Content-Transfer-Encoding: base64
    Content-ID: <part1.06090408.01060107>
    Content-Disposition: inline; filename="moz-screenshot.png"
    [base64 image data here]
    
    --boundary2--
    --boundary1--
    

然后它会起作用

评论

0赞 Peter Flynn 9/30/2015
在这个问题上苦苦挣扎。我已经完全按照上面编码,但图像没有出现(只是一个带有替代文本的框架;文本工作正常)。我的 Content-ID 是 <filename.jpg>所以我的 href=“cid:filename.jpg” -- Content-ID 和 cid: 的值或语法有什么特殊技巧吗?
0赞 Peter Flynn 9/30/2015
我与RFC2392进行了检查,CID 表达式似乎有效。但它仍然没有显示。
1赞 guettli 11/9/2016
我写了一个类似问题的答案,并创造了一个 ascii 艺术来解释结构:stackoverflow.com/a/40420648/633961
0赞 koalo 8/9/2023
对我来说,它只是以相反的方式工作。即从混合变为相关......
2赞 Peter 11/7/2014 #4

如果您使用“插入/图片”菜单功能插入图像文件,则 Outlook 和 Outlook Express 都可以生成这些多部分图像电子邮件格式,这可能会令人感兴趣。

显然,电子邮件类型必须设置为HTML(而不是纯文本)。

任何其他方法(例如拖放或任何命令行调用)都会导致图像作为附件发送。

如果您随后将这样的电子邮件发送给自己,您可以看到它的格式!:)

FWIW,我正在寻找一个独立的 Windows 可执行文件,它可以从命令行模式执行内联图像,但似乎没有。这是一条许多人都走过的道路......例如,可以通过向 Outlook Express 传递一个格式适当的 .eml 文件来做到这一点。

5赞 Brian 11/16/2014 #5

使用 Base64 在 html 中嵌入图像真是太棒了。尽管如此,请注意,base64 字符串会使您的电子邮件大小变大。

因此

1)如果您有很多图像,将图像上传到服务器并从服务器加载这些图像可以使您的电子邮件大小更小。(您可以通过Google获得很多免费服务)

2) 如果您的邮件中只有几张图片,使用 base64 字符串绝对是一个很棒的选择。

除了现有答案提供的选项外,您还可以使用命令在 linux 上生成 base64 字符串:

base64 test.jpg

评论

1赞 Mendy 1/3/2020
Michael Böckling 指出:电子邮件中的数据 URI 在许多主流客户端(如 gmail)中不受支持
2赞 Steven Newman 2/10/2015 #6
  1. 您需要 3 个边界才能使内联图像完全兼容。

  2. 一切都在里面。multipart/mixed

  3. 然后使用 to 包含您和您的图像附件标题。multipart/relatedmultipart/alternative

  4. 最后,将可下载的附件包含在 的最后一个边界内。multipart/mixed

评论

17赞 Makyen 2/10/2015
如果你包括一个例子,会很有帮助。
9赞 jbruni 3/25/2015
更有用的是对规范的引用。
41赞 Khyati Elhance 2/2/2017 #7

另一种解决方案是将图像附加为附件,然后使用 cid 引用它 html 代码。

HTML代码:

<html>
    <head>
    </head>
    <body>
        <img width=100 height=100 id="1" src="cid:Logo.jpg">
    </body>
</html>

C# 代码:

EmailMessage email = new EmailMessage(service);
email.Subject = "Email with Image";
email.Body = new MessageBody(BodyType.HTML, html);
email.ToRecipients.Add("[email protected]");
string file = @"C:\Users\acv\Pictures\Logo.jpg";
email.Attachments.AddFileAttachment("Logo.jpg", file);
email.Attachments[0].IsInline = true;
email.Attachments[0].ContentId = "Logo.jpg";
email.SendAndSaveCopy();

评论

1赞 jpr 6/24/2021
谢谢你的解决方案。在我的情况下,附加图像然后在 html 代码中引用它有效。
2赞 GerardV 9/10/2017 #8

实际上,有一篇非常好的博客文章列出了马丁·戴维斯(Martyn Davies)解决这个问题的三种不同方法的优缺点。您可以在 https://sendgrid.com/blog/embedding-images-emails-facts/ 上阅读它。

我想添加第四种使用CSS背景图像的方法。

<div id="myImage"></div>

添加到您的电子邮件正文和 CSS 类中,例如:

#myImage {
    background-image:  url('data:image/png;base64,iVBOR...[some more encoding]...rkggg==');
    width: [the-actual-image-width];
    height: [the-actual-image-height];
}
3赞 tstrand66 8/16/2018 #9

对于那些无法让这些解决方案之一起作用的人: 在电子邮件中发送内联图像 按照 @T30 提供的解决方案中列出的步骤,我能够让我的内联图像在不被 Outlook 阻止的情况下显示(以前的方法它被阻止了)。如果您像我们一样使用交换,那么在执行以下操作时也是如此:

service = new ExchangeService(ExchangeVersion);
service.AutodiscoverUrl("[email protected]");
SmtpClient smtp = new SmtpClient(service.Url.Host);

您需要将它传递给您的 Exchange 服务 URL 主机。除此之外,遵循此解决方案应该允许您轻松发送嵌入式 imgage。

7赞 Scooter Crawford 1/5/2019 #10

我知道这是一篇旧文章,但目前的答案并没有解决 Outlook 和许多其他电子邮件提供商不支持内联图像或 CID 图像的事实。在电子邮件中放置图像的最有效方法是在线托管图像并在电子邮件中放置指向它的链接。对于小型电子邮件列表,公共 Dropbox 工作正常。这也降低了电子邮件的大小。

0赞 Tarik 8/7/2019 #11

以下是使用两种实现此目的的方法的工作代码:

using System;
using Outlook = Microsoft.Office.Interop.Outlook;

namespace ConsoleApp2
{
    class Program
    {
        static void Main(string[] args)
        {

            Method1();
            Method2();
        }

        public static void Method1()
        {
            Outlook.Application outlookApp = new Outlook.Application();
            Outlook.MailItem mailItem = outlookApp.CreateItem(Outlook.OlItemType.olMailItem);
            mailItem.Subject = "This is the subject";
            mailItem.To = "[email protected]";
            string imageSrc = "D:\\Temp\\test.jpg"; // Change path as needed

            var attachments = mailItem.Attachments;
            var attachment = attachments.Add(imageSrc);
            attachment.PropertyAccessor.SetProperty("http://schemas.microsoft.com/mapi/proptag/0x370E001F", "image/jpeg");
            attachment.PropertyAccessor.SetProperty("http://schemas.microsoft.com/mapi/proptag/0x3712001F", "myident"); // Image identifier found in the HTML code right after cid. Can be anything.
            mailItem.PropertyAccessor.SetProperty("http://schemas.microsoft.com/mapi/id/{00062008-0000-0000-C000-000000000046}/8514000B", true);

            // Set body format to HTML

            mailItem.BodyFormat = Outlook.OlBodyFormat.olFormatHTML;
            string msgHTMLBody = "<html><head></head><body>Hello,<br><br>This is a working example of embedding an image unsing C#:<br><br><img align=\"baseline\" border=\"1\" hspace=\"0\" src=\"cid:myident\" width=\"\" 600=\"\" hold=\" /> \"></img><br><br>Regards,<br>Tarik Hoshan</body></html>";
            mailItem.HTMLBody = msgHTMLBody;
            mailItem.Send();
        }

        public static void Method2()
        {

            // Create the Outlook application.
            Outlook.Application outlookApp = new Outlook.Application();

            Outlook.MailItem mailItem = (Outlook.MailItem)outlookApp.CreateItem(Outlook.OlItemType.olMailItem);

            //Add an attachment.
            String attachmentDisplayName = "MyAttachment";

            // Attach the file to be embedded
            string imageSrc = "D:\\Temp\\test.jpg"; // Change path as needed

            Outlook.Attachment oAttach = mailItem.Attachments.Add(imageSrc, Outlook.OlAttachmentType.olByValue, null, attachmentDisplayName);

            mailItem.Subject = "Sending an embedded image";

            string imageContentid = "someimage.jpg"; // Content ID can be anything. It is referenced in the HTML body

            oAttach.PropertyAccessor.SetProperty("http://schemas.microsoft.com/mapi/proptag/0x3712001E", imageContentid);

            mailItem.HTMLBody = String.Format(
                "<body>Hello,<br><br>This is an example of an embedded image:<br><br><img src=\"cid:{0}\"><br><br>Regards,<br>Tarik</body>",
                imageContentid);

            // Add recipient
            Outlook.Recipient recipient = mailItem.Recipients.Add("[email protected]");
            recipient.Resolve();

            // Send.
            mailItem.Send();
        }
    }
}
0赞 Klendatho 3/15/2020 #12

Pavel Perna的帖子对我帮助很大(不能用我的声誉发表评论,这就是我发布这个作为答案的原因):在某些版本的Microsoft Exchange中,删除了内联内容处置(请参阅Microsoft的这篇文章)。该图像根本不是用户在 Outlook 中看到的邮件的一部分。解决方法是,请改用“Content-Disposition: attachement”。Outlook 2016 不会将邮件中使用的图像显示为附件,尽管它们使用“内容处置:附件”。

0赞 Vladimir Krasko 8/22/2020 #13

尝试使用 Context.Request 解决此问题:

<img width="150" height="60" src="@($"{Context.Request.Scheme}://{Context.Request.Host}{Context.Request.PathBase}/images/logo.png")" />

在我的情况下,当我使用 Content-ID 时,我也将该图像作为附件,这不是最好的解决方案。

评论

0赞 Paschal 3/25/2021
你能分享一个工作的例子吗?context.request 代表什么?
0赞 shinzou 3/23/2023
那些是什么?Context.Request.Scheme}://{Context.Request.Host}{Context.Request.PathBase
0赞 Vladimir Krasko 3/24/2023
@shinzou Context.Request 是 HttpRequest 类的实例,该类包含有关传入 HTTP 请求的信息,例如请求方法、URL、标头和正文。例如,如果您将图像放置在 wwwroot/images/logo 中.png则在本地测试时,此路径将是:[link] localhost:5000/images/logo.png在生产中,它将如下所示:[link] example.com/images/logo.png https 是 Scheme,localhost 或 www.example.com 是 Host,images 是 PathBase。我还没有详细测试,但这就是这个想法
0赞 shinzou 3/26/2023
所以我知道你必须把这些图像作为你的FE项目包的一部分发送,而且它们都必须是静态的。这是一个有限的解决方案。
0赞 Ajay Lamba 5/27/2023 #14

如果要使用 Microsoft EWS 服务在电子邮件中发送内联图像,可以将图像作为附件发送,并将其设置为内联。

以下是将 MIMEMessage 转换为 EmailMessage 的 java 代码片段:

ExchangeEwsConnection ewsConnection =
    ExchangeEwsSupport.getConnection(configuration, connectionDetails, false, true);
try {
  ExchangeService exchangeService =
      ExchangeEwsSupport.getExchangeService(configuration, ewsConnection, null);
  EmailMessage emailMessage = new EmailMessage(exchangeService);
  emailMessage.setSubject(message.getSubject());
  emailMessage.getToRecipients().add(new EmailAddress("[email protected]"));

  if (message instanceof MimeMessage) {
    MimeMessage mimeMessage = (MimeMessage) message;
    Multipart multipart = (Multipart) mimeMessage.getContent();
    for (int i = 0; i < multipart.getCount(); i++) {
      BodyPart bodyPart = multipart.getBodyPart(i);
      if (StringUtils.equalsIgnoreCase("text/html",
          bodyPart.getDataHandler().getContentType())) {
        emailMessage
            .setBody(new MessageBody(bodyPart.getDataHandler().getContent().toString()));
      }
      if (StringUtils.equalsIgnoreCase(bodyPart.getDisposition(), Part.INLINE)) {
        FileDataSource fileDataSource =
            ((FileDataSource) bodyPart.getDataHandler().getDataSource());
        File imageFile = fileDataSource.getFile();
        FileAttachment imageInlineAttachment = emailMessage.getAttachments().addFileAttachment(
            imageFile.getName(), new FileInputStream(imageFile.getAbsolutePath()));
        imageInlineAttachment.setContentType("image/png");
        imageInlineAttachment.setIsInline(true);
        String contentId =
            bodyPart.getHeader("Content-ID")[0];
        imageInlineAttachment.setContentId(contentId);

      } else if (StringUtils.equalsIgnoreCase(bodyPart.getDisposition(), Part.ATTACHMENT)) {
        FileDataSource fileDataSource =
            ((FileDataSource) bodyPart.getDataHandler().getDataSource());
        File file = fileDataSource.getFile();
        emailMessage.getAttachments().addFileAttachment(file.getName(), file.getAbsolutePath());
      }
    }
  }

  emailMessage.send();

} catch (Exception e) {
  logger.log(“Exception occurred, cause:”, e.getCause());
}

以下是将MIMEMessage转换为EmailMessage格式的分步指南 - https://azaylamba.medium.com/converting-mimemessage-to-emailmessage-while-sending-email-using-microsoft-ews-service-a-57137e281f53

它详细说明了如何在电子邮件中发送内联图像。