1. Original Entry + Comments2. Write a Comment3. Preview Comment
New comments for this entry are disabled.


August 17, 2005  |  System.Net.Mail and embedded images  |  77007 hit(s)

Finally stumbled upon the way to create email messages with embedded images in ASP.NET 2.0. (Note that this doesn't work for ASP.NET 1.1, sorry to say.)

For review ... you can add an image to an email message in these ways:
  • Attach it. Works ok, but it's ... attached. Illustrated earlier.
  • In an HTML-formatted message, create an <img> tag that points to an absolute URL.
  • In an HTML-formatted message, create an <img> tag that points to an embedded image and then (duh) embed the image. In that case, the image shows up inline with the message's text.

Pointing to an absolute URL keeps the message size down, but you have no control over the image on the server, and it could go away or change. Attaching and embedding keep a copy of the image with the message, but bloat the message size.

So, embedding. The trick, such as it is, is to create an alternative view and to add a linked resource to the alternative view. Alternative views enable you to create different versions of the email message -- typically one in plain text and the other formatted with HTML. These then substitute for the basic msg.Body property. Behind the scenes, the class creates the appropriately formatted multipart email that incorporates the alternative views, which lets the email client choose which one to use.

To do the actual embedding, you need to do a number of things:
  • Create an HTML-formatted message.
  • Use an <img> tag in the message body.
  • For the src attribute of the <img>, point not to a URL, but to a content ID (cid). This points to the portion of the message containing the image stream.
  • Create an alternative view.
  • Create a linkedResource that slurps up the image you want to embed.
  • Assign a content ID to the linked resource -- this should match the cid you used in the <img> tag.
  • Assign the image's file name to the linked resource.

(I think it takes more lines to describe it than to actually do it.)

Here's code. I can't take credit for it. I played with this for a long time trying to get it to work and came close, but I ultimately relied on an example provided by mharder in an internal email. Note the syntax of the <img> tag and the use of ContentId, ContentType.Name, and filename.
Imports System.Net.Mail
Imports System.Net.Mime
Imports System.IO


[...]


Dim fromAddress As String = "mike@elsewhere.com"
Dim toAddress As String = "mike@elsewhere.com"
Dim subject As String = "Test EmbeddedImage"
Dim contentId As String = "image1"
Dim path As String = Server.MapPath("~") & "\"
Dim filename As String = path & "MyPicture.jpg"
Dim body As String = "Here is a linked resource: <img src=""cid:image1""/>"


Dim mailMessage As New MailMessage(fromAddress, toAddress)
mailMessage.Subject = "Testing embedded image"
Dim av1 As AlternateView
av1 = AlternateView.CreateAlternateViewFromString(body, Nothing, _
MediaTypeNames.Text.Html)
Dim linkedResource As LinkedResource = New LinkedResource(filename)
linkedResource.ContentId = contentId
linkedResource.ContentType.Name = filename


av1.LinkedResources.Add(linkedResource)
mailMessage.AlternateViews.Add(av1)
mailMessage.IsBodyHtml = True
Dim mailSender As New SmtpClient("smtpHost")
Try
mailSender.Send(mailMessage)
labelStatus.Text = "Message sent!"
Catch ex As Exception
labelStatus.Text = ex.Message
End Try


System.Net.Mail ? ASP.Net 2.0    (Gollum's den)
? ??????? ??????? System.Net.Mail ????? ????? ???????? ?????? ? ???????????? ? ??????????? ??????????....





i have tried using Link resource and Alternate view the way you said and replaced the above URL text with cid:image1, but it doesn't seem to work.

Any suggestions?



 
Tman   21 Feb 06 - 5:21 AM

Thanx Mike!
Just great, hard to find good examples on this.


 
kory s.   26 Apr 06 - 1:40 PM

Thanks! Your example was simple and straight forward, works perfectly.

 
Stephen   17 Aug 06 - 6:39 AM

Another thanks for this blog entry... much more detailed than anything out there i found (including www.systemnetmail.com's non-working example)

 
Dana Stephenson   30 Aug 06 - 9:02 AM

Great post, worked perfectly on the first try! Thanks!

 
Kalesh   26 Oct 06 - 9:58 PM

Thanks mike for the article.
I facing one issue....I am not able to access the class AlternateView in my code..

can u help me...I am using dotnet 2.0


 
mike   26 Oct 06 - 10:58 PM

Have you imported all the right namespaces? Probably you have, but thought it was worth asking.

BTW, are you using Visual Studio? Do you see (for example) MailMessage but not AlternateView in IntelliSense?


 
Me   22 Nov 06 - 8:07 PM

So how would you do this thing in .NET 1.0?



 
mike   22 Nov 06 - 9:03 PM

For 1.1, have a look at the discussion here:


http://www.systemwebmail.com/faq/3.3.aspx

Effectively, you can't do it natively with System.Web.Mail. There is a long thread of discussions in the comments that might be interesting.


 
Dan Clem   24 Jan 07 - 2:09 PM

Thanks for posting this. You showed the correct way of doing something that the MSDN site was showing incorrectly:

http://msdn2.microsoft.com/en-us/library/system.net.mail.mailmessage.alternateviews.aspx


 
Anonymous   07 Feb 07 - 12:49 PM

great! thanks!

 
peter   07 Feb 07 - 3:20 PM

Also if you want to build the email-sending-with-embedded-images functionality into a class library and include the jpg files into the DLL as embedded resources rather than referencing the files located in some web app:

* add your jpegs to your class library project, mark their Build Action property as Embedded Resource
* (say you've placed the "emailheader.jpg" image in the \EmbeddedImages\ folder inside your project)
* than do this

string imgHeaderName = Assembly.GetExecutingAssembly().GetName().Name + ".EmbeddedImages.emailheader.jpg";

Stream streamImageHeader = Assembly.GetExecutingAssembly().GetManifestResourceStream(imgHeaderName);

if (streamImageHeader != null)
{
LinkedResource lrImageHeader = new LinkedResource(streamImageHeader);
lrImageHeader.ContentId = CIDHEADER;
av.LinkedResources.Add(lrImageHeader);
}


where the av is the AlternateView object and CIDHEADER is the cid value from the email body.


 
longnguyen   14 Jun 07 - 1:11 AM

Public Function SendMailMessage(ByVal FromAddress As String, ByVal ToAddresses As String, ByVal Subject As String, ByVal Body As String, ByVal IsHTML As Boolean, ByVal ServerName As String, ByVal Port As Integer, ByVal UserName As String, ByVal PassWord As String) As Integer
Dim k As Integer = 0
Dim Message As New MailMessage
Dim smtp As New SmtpClient(ServerName, Port)
Message.From = New MailAddress(FromAddress)
Message.To.Add(ToAddresses)
Dim strMailContent As String
strMailContent = Body

Dim av1 As AlternateView = AlternateView.CreateAlternateViewFromString(strMailContent, Nothing, "Text/Html")
av1.TransferEncoding = Net.Mime.TransferEncoding.Base64
Message.AlternateViews.Add(av1)
Message.BodyEncoding = System.Text.Encoding.GetEncoding("utf-8") 'windows-1252") 'set the proper character set here
Message.Subject = Subject
Message.IsBodyHtml = IsHTML
Message.Priority = MailPriority.High
smtp.Credentials = New System.Net.NetworkCredential(Trim(UserName), Trim(PassWord))

'smtp.EnableSsl = True
Try
smtp.Send(Message)
k = 1
Catch ex As Exception
k=0
End Try
SendMailMessage = k
End Function


 
Gurpreet S Bakshi   20 Jul 07 - 2:04 PM

This is a great example. Works perfect where the case is to you an <IMG tag. Do you know a way to embed an image for a background-image property within the style of a particular element?

<td style="background-image: url(Images/BlueExplorer.gif);">Some Text Here
mat   14 Aug 07 - 4:22 AM

thx mike you saved the day!!!!

 
Charlie   20 Aug 07 - 9:27 AM

Mike,

With outlook 2003 as the client this code works, but the image is still attached as a radomly named jpg and the html is also attached with another random name.

How can i avoid having the .htm and .jpg files showing up at all? Its quite important to my project that these don't show up.

Hope you can help.


 
mike   20 Aug 07 - 11:13 AM

@charlie -- I don't know what's wrong. I just tried it, and it worked perfectly in Outlook 2003. I can't help but think that it's some sort of configuration with the email client. If you send it to another client (e.g. gmail), perhaps it will work differently -- ?

In any event, I'm going to advise that if that doesn't work, you post a query on the ASP.NET forums (http://forums.asp.net). Since I can't repro the problem, I'm afraid I can't really help debug it. :-(


 
MAnoj   20 Feb 08 - 12:47 AM

THANKS A LOT!!!
EXATLY WHAT I WAS SEARCHING FOR...