169

I'm trying to send a multipart/related html email with embedded gif images. This email is generated using Oracle PL/SQL. My attempts have failed, with the image showing up as a red X (in Outlook 2007 and yahoo mail)

I've been sending html emails for some time, but my requirements are now to use several gif images in the email. I can store these on one of our web servers and just link to them, but many users email clients will not show them automatically and will need to either change settings or manually download them for each email.

So, my thoughts are to embed the image. My questions are:

  1. What am I doing wrong here?
  2. Is the embedding approach the correct one?
  3. Any other options if I need to use more and more images? Attachments won't work, as the images are typically logos and icons that won't make sense out of the context of the message. Also, some elements of the email are links into an online system, so generating a static PDF and attaching won't work (to my knowledge anyway).

snippet:

MIME-Version: 1.0
To: me@gmail.com
BCC: me@yahoo.com
From: email@yahoo.com
Subject: Test
Reply-To: email@yahoo.com
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--

Many thanks.

BTW: Yes, I have verified that the base64 data is correct, as I can embed the image in the html itself (using same algo use for creating header data) and see image in Firefox/IE.

I should also note that this is NOT for spam, the emails are sent to specific clients who are expecting it daily. The content is data-driven, and not adverts.

tbone
  • 15,107
  • 3
  • 33
  • 40
  • Quick question: are you hosting these images off-site or embedding them directly into the email? – JonLim Jul 15 '11 at 17:47
  • Part of my question really, I can do either. I'm try here to embed them, but not sucessfully. If I just link to them, many users won't see the images without downloading them first, which I'd like to avoid. – tbone Jul 15 '11 at 17:52
  • 1
    A regular `` worked for me, but it was an image that I hosted off-site. That doesn't work for you? – JonLim Jul 15 '11 at 18:05
  • "works" is subjective...yes, it works if the user is willing to download the images each time, but I'd like to avoid that and embed the image. – tbone Jul 15 '11 at 18:08
  • Just spent a bit of time looking at the embedded images from emails in my inbox, and I can't seem to crack it. Your code looks like it would work for an embed... – JonLim Jul 15 '11 at 18:18
  • 1
    @JonLim: thanks for looking into it, see my comments in the answer for what I was missing. – tbone Jul 15 '11 at 19:03
  • if you want inline images that works also in gmail look at this answer visit http://stackoverflow.com/a/1607263/2613863 – yehonatan yehezkel Dec 22 '16 at 15:33
  • Useful answer [here](https://stackoverflow.com/a/40420648/448078) that explains email structure – Mike Oct 05 '22 at 15:13

14 Answers14

177

Try to insert it directly, this way you can insert multiple images at various locations in the email.

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

And to make this post usefully for others to: If you don't have a base64-data string, create one easily at: http://www.motobit.com/util/base64-decoder-encoder.asp from a image file.

Email source code looks something like this, but i really cant tell you what that boundary thing is for:

 To: email@email.de
 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--

//EDIT: Oh, i just realize if you insert the first code snippet from my post to write an email with thunderbird, thunderbird automatically changes the html code to look pretty much the same as the second code in my post.

Mike
  • 23,542
  • 14
  • 76
  • 87
Bernd
  • 2,069
  • 1
  • 14
  • 8
  • 5
    tried this first, it doesn't work for me for email. works fine for viewing in IE/Firefox, but not sent as email. – tbone Jul 15 '11 at 18:06
  • Perhaps u know a way (what would the content type be? text/html? the email headers I'd need to know to send a mixed html/image file this way) – tbone Jul 15 '11 at 18:13
  • The code works for me when sending and receiving email via thunderbird. Just tested it, to be sure. – Bernd Jul 15 '11 at 18:18
  • Thank you for posting the headers! It works! I believe I was missing the "name=" and "filename=" parts in the image section. Also, I changed to use png instead of gif. – tbone Jul 15 '11 at 18:54
  • Could any of you folks please tell us what Oracle package you used to send the email? Utl_mail.send does not have any parameter called "boundary". This information would be useful to other visitors to SO. – Zesty Mar 04 '12 at 08:05
  • 1
    @Zesty use @[username] to alert someone, just saw your question. I use utl_smtp. For me, I had to create build a clob with the html body, boundaries, etc and then send via utl_smtp. See here for simple example: http://www.oracle-base.com/articles/misc/EmailFromOraclePLSQL.php Note that this link does not show embedded images approach, but has detail to get you going. – tbone Mar 09 '12 at 15:19
  • @[tbone] Thanks for both pieces of information! This is just what I needed. – Zesty Mar 11 '12 at 10:40
  • 67
    Data URIs in emails aren't supported in many mainstream clients and should not be used, see: https://www.campaignmonitor.com/blog/post/3927/embedded-images-in-html-email – Michael Böckling Oct 28 '14 at 10:37
  • 2
    It does not seem to work in hotmail / icloud =( did I miss anything – hsb1007 Apr 27 '15 at 00:51
  • I have used base64 encoding and I am sending the email to outlook. But outlook truncates my encoded data of the image, although everything else remains same as what was sent from the application. Because of this image is not appearing on the body of the email. Please help. – paper.plane Nov 28 '16 at 13:23
  • This approach doesn't work as almost all the major email providers and web email clients block it. – Cesar Jan 05 '21 at 12:43
41

The other solution is attaching the image as attachment and then referencing it html code using cid.

HTML Code:

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

C# Code:

EmailMessage email = new EmailMessage(service);
email.Subject = "Email with Image";
email.Body = new MessageBody(BodyType.HTML, html);
email.ToRecipients.Add("abc@xyz.com");
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();
Abzoozy
  • 874
  • 12
  • 26
Khyati Elhance
  • 662
  • 6
  • 11
  • 1
    Thank you for the solution. Attaching the image and then referencing it in html code worked in my case. – jpr Jun 24 '21 at 07:00
16

I don't find any of the answers here useful, so I am providing my solution.

  1. The problem is that you are using multipart/related as the content type which is not good in this case. I am using multipart/mixed and inside it multipart/alternative (it works on most clients).

  2. The message structure should be as follows:

    [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--
    

Then it will work

msrd0
  • 7,816
  • 9
  • 47
  • 82
Pavel Perna
  • 359
  • 2
  • 10
  • Struggling on this one. I have coded exactly as above, but the image is not appearing (just a frame with the alt text; the text works fine). My Content-ID is so my href="cid:filename.jpg" -- is there some special trick to the value or syntax of Content-ID and cid: ? – Peter Flynn Sep 30 '15 at 14:52
  • I checked with RFC2392 and the CID expression appears to be valid. But it still doesn't display. – Peter Flynn Sep 30 '15 at 15:44
  • 1
    I wrote an answer to a similar question and created an ascii art to explain the structure: http://stackoverflow.com/a/40420648/633961 – guettli Nov 09 '16 at 08:50
  • For me it just worked the other way around. I.e. change from mixed to related... – koalo Aug 09 '23 at 12:28
11

If it does not work, you may try one of these tools that convert the image to an HTML table (beware the size of your image though):

Erwin Mayer
  • 18,076
  • 9
  • 88
  • 126
  • 18
    img2hmtl is the wackiest solution / idea I have seen in a while. +1 – Kristjan Liiva Jul 28 '17 at 10:57
  • 1
    ...where the term "wacky" summarizes this feature of img2html: *As a solution, we wrote an app that converts each pixel of an image into a corresponding HTML cell.* – Red Pill Feb 24 '23 at 09:06
7

I know this is an old post, but the current answers dont address the fact that outlook and many other email providers dont support inline images or CID images. The most effective way to place images in emails is to host it online and place a link to it in the email. For small email lists a public dropbox works fine. This also keeps the email size down.

5

Using Base64 to embed images in html is awesome. Nonetheless, please notice that base64 strings can make your email size big.

Therefore,

1) If you have many images, uploading your images to a server and loading those images from the server can make your email size smaller. (You can get a lot of free services via Google)

2) If there are just a few images in your mail, using base64 strings is definitely an awesome option.

Besides the choices provided by existing answers, you can also use a command to generate a base64 string on linux:

base64 test.jpg
Brian
  • 30,156
  • 15
  • 86
  • 87
  • 1
    Pointed out by Michael Böckling: data URIs in emails aren't supported in many mainstream clients like gmail – Mendy Jan 02 '20 at 22:18
3

For those who couldnt get one of these solutions working: Send inline image in email Following the steps laid out in the solution offered by @T30 i was able to get my inline image to display without being blocked by outlook (previous methods it was blocked). If you are using exchange like we are then also when doing:

service = new ExchangeService(ExchangeVersion);
service.AutodiscoverUrl("email@domain.com");
SmtpClient smtp = new SmtpClient(service.Url.Host);

you will need to pass it your exchange service url host. Other than that following this solution should allow you to easily send embedded imgages.

tstrand66
  • 968
  • 7
  • 11
2

It may be of interest that both Outlook and Outlook Express can generate these multipart image email formats, if you insert the image files using the Insert / Picture menu function.

Obviously the email type must be set to HTML (not plain text).

Any other method (e.g. drag/drop, or any command-line invocation) results in the image(s) being sent as an attachment.

If you then send such an email to yourself, you can see how it is formatted! :)

FWIW, I am looking for a standalone windows executable which does inline images from the command line mode, but there seem to be none. It's a path which many have gone up... One can do it with say Outlook Express, by passing it an appropriately formatted .eml file.

Peter
  • 21
  • 2
2
  1. You need 3 boundaries for inline images to be fully compliant.

  2. Everything goes inside the multipart/mixed.

  3. Then use the multipart/related to contain your multipart/alternative and your image attachment headers.

  4. Lastly, include your downloadable attachments inside the last boundary of multipart/mixed.

Yurii
  • 4,811
  • 7
  • 32
  • 41
2

There's actually a very good blog post that lists pro's and cons of three different approaches to this problem by Martyn Davies. You can read it at https://sendgrid.com/blog/embedding-images-emails-facts/.

I'd like to add a fourth approach using CSS background images.

Add

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

to your e-mail body and a css class like:

#myImage {
    background-image:  url('data:image/png;base64,iVBOR...[some more encoding]...rkggg==');
    width: [the-actual-image-width];
    height: [the-actual-image-height];
}
GerardV
  • 375
  • 2
  • 11
0

The following is working code with two ways of achieving this:

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 = "john@example.com";
            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("john@example.com");
            recipient.Resolve();

            // Send.
            mailItem.Send();
        }
    }
}
Tarik
  • 10,810
  • 2
  • 26
  • 40
0

One additional hint to Pavel Perna's post which helped me very much (cannot comment with my reputation, that's why I post this as answer): In some versions of Microsoft Exchange, the inline contents disposition is removed (see this post by Microsoft). The image is simply not part in the mail the user sees in Outlook. As a workaround, use "Content-Disposition: attachement" instead. Outlook 2016 won't show images as attachement that are used in the mail message, although they use the "Content-Disposition: attachement".

Klendatho
  • 153
  • 1
  • 7
0

Try to resolve that with Context.Request:

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

In my situation, when I used Content-ID I had that image as an attachment as well, and that was not the best solution.

  • Can you share a working example? What does the context.request stand for? – Paschal Mar 25 '21 at 11:25
  • what are those? Context.Request.Scheme}://{Context.Request.Host}{Context.Request.PathBase – shinzou Mar 22 '23 at 17:06
  • @shinzou Context.Request is instance of the HttpRequest class which contains information about an incoming HTTP request, such as the request method, URL, headers, and body. For example, if you have image placed in wwwroot/images/logo.png than if you test locally this path would be: [link] https://localhost:5000/images/logo.png in production it would be like this: [link] https://www.example.com/images/logo.png https is Scheme, localhost or www.example.com is Host, images is PathBase. I haven't tested in detail, but that is the idea – Vladimir Krasko Mar 24 '23 at 10:03
  • So I understand you have to send those images as part of your FE project bundle, and they all have to be static. This is a limited solution. – shinzou Mar 26 '23 at 09:03
0

If you want to send inline images in emails using Microsoft EWS service, you can send the image as an attachment and set it as inline.

Following is the java code snippet to convert a MIMEMessage to EmailMessage:

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("abc@example.com"));

  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());
}

Following is a step by step guide to convert a MIMEMessage to EmailMessage format - https://azaylamba.medium.com/converting-mimemessage-to-emailmessage-while-sending-email-using-microsoft-ews-service-a-57137e281f53

It has detailed explanation of how to send inline image in the email.

Ajay Lamba
  • 71
  • 5