Click here to Skip to main content
15,879,326 members
Articles / Programming Languages / C#
Tip/Trick

Embedding an Image Inside an HTML Email

Rate me:
Please Sign up or sign in to vote.
5.00/5 (7 votes)
3 Dec 2013CPOL2 min read 42.8K   10   8
Clear guide on how to embed an image inside an HTML email

Introduction

Sometimes, I feel like the BASF Corporation of coding, I take other people's code and improve upon it. So I was looking for a sample on embedding an image in an HTML email and I found this. Since it had a few issues, I decided to make it somewhat better.

Using the Code

It is really quite simple:

C#
namespace ConsoleApplication1
{
    using System;
    using System.Net.Mail;
    using System.Net.Mime;
    using System.Text;
    using System.Xml.Linq;

    internal class Program
    {
        #region Methods

        private static void Main(string[] args)
        {
            const string To = "darek@somewhere.com";
            const string From = "noreply@somewhere.com";
            var message = new MailMessage(From, To)
                          {
                              Subject = "Sending email with embedded attachment",
                              IsBodyHtml = true
                          };
            Guid newGuid = Guid.NewGuid();
            message.Headers.Add("Message-ID", newGuid.ToString());
            var messageBody = new XElement
            ("html", new XElement("body", 
              new XElement("img", 
              new XAttribute("src", "cid:DarekCartoon"))));
            AlternateView av = AlternateView.CreateAlternateViewFromString(
              messageBody.ToString(SaveOptions.DisableFormatting), 
              Encoding.Unicode, MediaTypeNames.Text.Html);
            av.LinkedResources.Add(
                new LinkedResource("DarekCartoon.jpeg")
                {
                    ContentId = "DarekCartoon"
                });
            message.AlternateViews.Add(av);
            using (var client = new SmtpClient("smtp.somewhere.com"))
            {
                client.UseDefaultCredentials = true;
                try
                {
                    client.Send(message);
                }
                catch (Exception ex)
                {
                    Console.WriteLine("Exception caught: {0}", ex);
                }
            }
        }

        #endregion
    }
}

Assuming you've had a cartoon version of a picture of yours truly, in the same directory where the code executes, it will send out an "empty" email with just the image embedded inside. It will still show up as an attachment in Outlook's conversation view, but when you open it, there will be no attachment to save. The key takeaway is that your LinkedResource ContentId property value must be equal to the value of the image's src attribute with a prefix of "cid:", in the example above, they are "DarekCartoon" and "cid:DarekCartoon", respectively.

So what makes it better, you ask? Well ...

  1. It also shows how to assign a unique ID to the message, so you can track it in the future
  2. You don't have to pay much attention to the HTML syntax, since using XElement pretty much guarantees that all braces and quotes will be taken care of (original bug of the previous sample code)
  3. It does not let code guess the encoding type to use
  4. It allows for more programmatic generation of the content, without expensive string concatenation (remember, strings are not mutable)
  5. It disposes instances properly

I have confirmed that the image correctly shows in Outlook 2013 and Gmail.

Update - Being More Specific About Content Types and CSS Formatting

As Werner pointed out in his excellent article, sometimes, you might be forced to specify an image type and encoding. Also, when font formatting is important, you must add a CSS element, to define font formats and sizes to use. Here is how the relevant code would look like:

C#
var messageBody = new XElement(
    "html",
    new XElement("head", new XElement("style", 
    "P { font-family: sans-serif;font-size: small; }")),
    new XElement(
        "body",
        new XElement("P", new XElement("img", 
        new XAttribute("src", "cid:DarekCartoonJpeg")), 
        new XElement("BR"), "JPEG Image"),
        new XElement("P", new XElement("img", 
        new XAttribute("src", "cid:DarekCartoonTiff")), 
        new XElement("BR"), "TIFF Image"),
        new XElement("P", new XElement("img", 
        new XAttribute("src", "cid:DarekCartoonGif")), 
        new XElement("BR"), "GIF Image")));
AlternateView av = AlternateView.CreateAlternateViewFromString
	(messageBody.ToString(SaveOptions.DisableFormatting), 
	Encoding.Unicode, MediaTypeNames.Text.Html);
av.LinkedResources.Add(
    new LinkedResource("DarekCartoon.jpeg")
    {
        ContentId = "DarekCartoonJpeg",
        ContentType = new ContentType
                      {
                          MediaType = MediaTypeNames.Image.Jpeg
                      },
        TransferEncoding = TransferEncoding.Base64
    });
av.LinkedResources.Add(
    new LinkedResource("DarekCartoon.tif")
    {
        ContentId = "DarekCartoonTiff",
        ContentType = new ContentType
                      {
                          MediaType = MediaTypeNames.Image.Tiff
                      },
        TransferEncoding = TransferEncoding.Base64
    });
av.LinkedResources.Add(
    new LinkedResource("DarekCartoon.gif")
    {
        ContentId = "DarekCartoonGif",
        ContentType = new ContentType
                      {
                          MediaType = MediaTypeNames.Image.Gif
                      },
        TransferEncoding = TransferEncoding.Base64
    });
message.AlternateViews.Add(av); 

Before I create the body of the message, I add a new HEAD element, in which I created a STYLE element, which allows me to specify font type and size for the HTML paragraphs. Then inside the body, I add all three image place holders, with titles, and proceed with embedding three different image types, Jpeg, Tiff, and Gif. They are the same image, just in different formats. This is only to demonstrate how to embed each image type.

Surprisingly, the PNG format is absent from the supported Image MediaTypes, however, adding it without specific ContentType, still works.

C#
av.LinkedResources.Add(
  new LinkedResource("DarekCartoon.Png")
  {
      ContentId = "DarekCartoonPng",
      TransferEncoding = TransferEncoding.Base64
  });

However, if you truly require to specify the format, you can do it like so:

C#
av.LinkedResources.Add(
  new LinkedResource("DarekCartoon.Png")
  {
      ContentId = "DarekCartoonPng",
      TransferEncoding = TransferEncoding.Base64,
      ContentType = new ContentType("image/png")
  });

Enjoy!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect BI Software, Inc.
United States United States
A seasoned IT Professional. Programming and data processing artist. Contributor to StackOverflow.

Comments and Discussions

 
QuestionWon't work with all other image types/email clients. Pin
Werner van Deventer3-Dec-13 6:47
Werner van Deventer3-Dec-13 6:47 
AnswerRe: Won't work with all other image types/email clients. Pin
Darek Danielewski3-Dec-13 7:02
Darek Danielewski3-Dec-13 7:02 
GeneralRe: Won't work with all other image types/email clients. Pin
Eduardo Antonio Cecilio Fernandes3-Dec-13 13:19
Eduardo Antonio Cecilio Fernandes3-Dec-13 13:19 
GeneralRe: Won't work with all other image types/email clients. Pin
Werner van Deventer3-Dec-13 17:36
Werner van Deventer3-Dec-13 17:36 
GeneralMy vote of 5 Pin
fredatcodeproject2-Dec-13 23:27
professionalfredatcodeproject2-Dec-13 23:27 
GeneralRe: My vote of 5 Pin
Darek Danielewski3-Dec-13 6:42
Darek Danielewski3-Dec-13 6:42 
GeneralMy vote of 5 Pin
abdurahman ibn hattab2-Dec-13 20:23
abdurahman ibn hattab2-Dec-13 20:23 
GeneralRe: My vote of 5 Pin
Darek Danielewski3-Dec-13 6:42
Darek Danielewski3-Dec-13 6:42 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.