C#: Embedding images in an email

April 22, 2010 by C#  

To send a simple text based e-mail (using .net), we simply instantiate a MailMessage class and pass the object to a SmtpClient class like this:

using System.Net.Mail;
using System.Net;

class Program
{
    static void Main(string[] args)
    {
        using (MailMessage mail = new MailMessage())
        {
            mail.To.Add("jane@doe.com");
            mail.From = new MailAddress("john@doe.com", "John Doe");
            mail.Subject = "Test subject";
            mail.Body = "Test body";
            SmtpClient SmtpMail = new SmtpClient("smtp.doe.com");
            
	/*	If authentication is needed on your smtp server
		SmtpMail.Credentials = new NetworkCredential("someusername", "somepassword");
	*/
			
            SmtpMail.Send(mail);
        }
    }
}

To send a HTML based email is equally as simple, simply set the IsBodyHtml property true on your MailMessage instance and pass some HTML to your body property.

But what about things like embedding images in an email (title of this post ;))?

One method I saw involves adding base64 encoded strings to image tags within the html e.g.
<img src="data:image/jpeg;base64,/4AASCDVCAGDFG//ASDFSDF....etc" />

Unfortunately a lot of email clients dislike this method (not to mention spam filters).

Another more common method is to add multipart entities to an e-mail and referencing them from cid's e.g.
<img src="cid:img1" />

We achieve that using the LinkedResource and AlternateView classes in .net.

What we're going to do, is create two files, template1.txt and template1.html.

template1.txt (contains the text part of the email)
Dear {recipient}

I would like to introduce you to our exciting website, please visit
CSTruter.com 

Yours Sincerely
{author}

template1.htm (contains the html part of the email)
<html>
<head>
    <title></title>
</head>
<body>
    Dear {recipient}
    <br />
    <br />
    I would like to introduce you to our exciting website, please visit<br />
    <a href="http://www.cstruter.com">CSTruter.com</a>
    <br />
    <br />
    Yours Sincerely
    <br />
    {author}
    <br />
    <img src="cid:img1" alt="Author" />
</body>
</html>

You might have noticed {recipient} & {author}, these are placeholders that we're going to populated via code.

In the following snippet we process the templates and send the email to our recipient:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Mail;
using System.Net;
using System.Net.Mime;
using System.IO;

class Program
{
    static AlternateView CreateAlternateViewFromTemplate(String path, String mediaType, IDictionary<String, String> replacements)
    {
        using (StreamReader sr = new StreamReader(path))
        {
            String content = sr.ReadToEnd();

            if (replacements != null)
            {
                foreach (KeyValuePair<String, String> replacement in replacements)
                {
                    content = content.Replace(String.Concat("{", replacement.Key, "}"), replacement.Value);
                }
            }

            AlternateView view = AlternateView.CreateAlternateViewFromString(content, Encoding.UTF8, mediaType);
            view.ContentType.CharSet = Encoding.UTF8.BodyName;
            if (mediaType == "text/html")
            {
                view.TransferEncoding = TransferEncoding.QuotedPrintable;
            }
            return view;
        }
    }

    static void Main(string[] args)
    {
        using (MailMessage mail = new MailMessage())
        {
            mail.To.Add("jane@doe.com");
            mail.From = new MailAddress("john@doe.com", "John Doe");
            mail.Subject = "Test subject";
            mail.Body = "test";
            Dictionary<String, String> replacements = new Dictionary<string, string>();
            replacements.Add("recipient", "Jane Doe");
            replacements.Add("author", "John Doe");
          
            AlternateView plain = CreateAlternateViewFromTemplate("template1.txt", "text/plain", replacements);
            AlternateView html = CreateAlternateViewFromTemplate("template1.htm", "text/html", replacements);

            LinkedResource img1 = new LinkedResource(@"cow.jpg", "image/jpeg");
            img1.ContentId = "img1";

            html.LinkedResources.Add(img1);
            mail.AlternateViews.Add(plain);
            mail.AlternateViews.Add(html);
            
            SmtpClient SmtpMail = new SmtpClient("smtp.doe.com");
            //SmtpMail.Credentials = new NetworkCredential("someusername", "somepassword");
            SmtpMail.Send(mail);
        }
    }
}

Note, we add a LinkedResource (the embedded resource, assign a ContentID to it - the cid needed for referencing the image in the HTML) to an AlternateView, and an AlternateView to our MailMessage instance.

It might also be interesting to have a look at the MailDefinition class, available within System.Web.UI.WebControls namespace - perhaps a future post ;)


Leave a Comment


Please elaborate January 11, 2016 by Christoff

Hi Peter, can you please elaborate on your issue? (Seeing that alternatives were given in this post)

Any workaround for sending email with base64 images January 11, 2016 by Peter Godfrey

Please I need workaround with <img src="data:image/jpeg;base64,/4AASCDVCAGDFG//ASDFSDF....etc" />

Great example December 5, 2012 by Anonymous

Very nice example. You saved me lots of work. Thanks!!

Ligpunt June 10, 2011 by Gatvol vir dom mense

Thank you Christoff. As always, an easy to understand and reusable post!