How to embed an Image Stream to MailMessage
Asked Answered
F

6

19

I'm having some difficulty embedding an image from the Properties.Resources to a MailMessage, currently the image does not show in the email i receive.

I have successfully embedded the image from a directory location but would prefer if the image came from memory/the application.

Here is a simplified version of what I am doing.

 Bitmap b = new Bitmap(Properties.Resources.companyLogo);
 MemoryStream logo = new MemoryStream();
 b.Save(logo, ImageFormat.Jpeg);



 MailMessage newEmail = new MailMessage(from, to);
 newEmail.Subject = subject;
 newEmail.IsBodyHtml = true;

 LinkedResource footerImg = new LinkedResource(logo, "image/jpeg");
 footerImg.ContentId = "companyLogo";
 AlternateView foot= AlternateView.CreateAlternateViewFromString(body + "<p> <img src=cid:companyLogo /> </p>", null, "text/html");

 foot.LinkedResources.Add(footerImg);

 newEmail.AlternateViews.Add(foot);             

 SmtpClient server = new SmtpClient(host, port);
 server.Send(newEmail);
Futtock answered 7/6, 2011 at 7:33 Comment(2)
where does "head" come from, and what do you do with "foot"?Steffens
that is irrelevant(but i made a rename mistake when copying out the source), either way i've solved the problem - Short answer is don't use Bitmap.Save instead convert the image to a Byte[] and instantiate the MemoryStream with it. I will post the full answer later.Futtock
F
28

Ok i have solved the problem.

Instead of using the BitMap save method I converted the BitMap to Byte[] and gave the memory stream the Byte[]

Did not work :

 b.Save(logo, ImageFormat.Jpeg);

Did Work:

Bitmap b = new Bitmap(Properties.Resources.companyLogo);
ImageConverter ic = new ImageConverter();
Byte [] ba = (Byte[]) ic.ConvertTo(b,typeof(Byte[]));
MemoryStream logo = new MemoryStream(ba);

I think it has something to do with the Bitmap.Save method, in the MSDN lib it mentioned that the stream has to have an offset of 0.

Futtock answered 8/6, 2011 at 13:51 Comment(1)
Just tell us, bro, how did you discover this approach? +1Rutter
A
23
Bitmap b = new Bitmap(Properties.Resources.companyLogo);
MemoryStream logo = new MemoryStream();
b.Save(logo, ImageFormat.Jpeg);

After you do the save, you have to "seek" the MemoryStream back to the start.

logo.Position = 0;
Adrianneadriano answered 11/2, 2012 at 11:35 Comment(1)
I wanted to use this approach and couldn't get it to work. Attachment was always 0 sized. Setting the position to 0 did the trick! @Adrianneadriano Thanks so much :-)Guarded
K
3

You can embed the image and skip working with resources by converting it to base64 instead:

public static string BitmapToBase64(Bitmap b)
{
   ImageConverter ic = new ImageConverter();
   byte[] ba = (byte[])ic.ConvertTo(b, typeof(byte[]));
   return Convert.ToBase64String(ba, 0, ba.Length);
}

and use it as html image src :

string logoimage="<img src='data:image/png;base64," + BitmapToBase64(logo) + "'>";

Note that converting to Base64 slighly increases the size of the image.

Kandis answered 25/12, 2019 at 20:52 Comment(1)
Unfortunately some webmail clients don't work too well with base64 embedded images. See https://mcmap.net/q/176516/-base64-images-to-gmailPopulous
H
0

Try look here:

http://www.eggheadcafe.com/community/aspnet/2/10219822/send-mail-with-atttached-image.aspx

From the link above:

static void EmbedImages()
{
   var mail = new MailMessage();

   mail.From = new MailAddress("[email protected]");
   mail.To.Add("[email protected]");
   mail.Subject = "This is an email";

   var plainView = AlternateView.CreateAlternateViewFromString(
      "This is my plain text content, viewable by those clients that don't support html",
      null, "text/plain");

   var htmlView = AlternateView.CreateAlternateViewFromString(
      "Here is an embedded image.<img src=cid:companylogo>", 
      null, "text/html");

   LinkedResource logo = new LinkedResource( "c:\\temp\\logo.gif" );
   logo.ContentId = "companylogo";

   htmlView.LinkedResources.Add(logo);

   mail.AlternateViews.Add(plainView);
   mail.AlternateViews.Add(htmlView);

   var smtp = new SmtpClient("127.0.0.1"); //specify the mail server address
   smtp.Send(mail);
}
Holmen answered 7/6, 2011 at 7:36 Comment(5)
I know that works - adding the image from a location - but i would like to use the Application's resources. The LinkedResource has an overload to take a Stream instead of the file location. I tried to use that but either the initial image -> stream is not working or the embedding of the image's stream -> LinkedResourceFuttock
He asked about to use Bitmap and MemoryStream and not the direct image file...Rutter
Watch out - MailMessage and SmtpClient implement IDisposable so should be in a using statement or disposed manually.Unorganized
This isn't related the the OPs question.Cyr
If I add both views, html and plain, then when receiving emails it always shows in plain mode. If I add only html then it always shows html. Is there a way to prioritize this, so it first tries to load html view if something goes wrong then it loads the plain?Workmanlike
G
0

Instead of adding the "logo" to Resources, I added it directly to the project and set it to build as an "Embedded Resource".

Then using System.Reflection.Assymbly I can get it (I assume directly) as a Stream:

  var _assembly = Assembly.GetExecutingAssembly();
  var _logoStream = _assembly.GetManifestResourceStream("[Project].[Filename].png");
  var logo = new LinkedResource(_logoStream, "image/png");
  logo.ContentId = "Logo";
  html.LinkedResources.Add(logo);
Gand answered 15/8, 2017 at 0:56 Comment(0)
C
0

Here's how I implemented it:

var htmlBody = "...<img src=\"cid:logo.jpg\" />...";
    
var message = new MailMessage();
message.To.AddRange(mailAddresses);
message.From = fromAddress;

var plaintextView = AlternateView.CreateAlternateViewFromString(plaintextBody, new ContentType(MediaTypeNames.Text.Plain));
plaintextView.ContentType.CharSet = Encoding.UTF8.WebName;
message.AlternateViews.Add(plaintextView);
    
var logoLinkedResource = new LinkedResource(new MemoryStream(Properties.Resources.Logo), MediaTypeNames.Image.Jpeg)
{
    ContentId = "logo.jpg",
    TransferEncoding = TransferEncoding.Base64
};
    
var htmlView = AlternateView.CreateAlternateViewFromString(htmlBody, new ContentType(MediaTypeNames.Text.Html));
htmlView.ContentType.CharSet = Encoding.UTF8.WebName;
htmlView.LinkedResources.Add(logoLinkedResource);
message.AlternateViews.Add(htmlView);
    
message.Subject = subject;

This is fairly similar to some of the above answers, but a little different, and took me a while to get the details right for my case.

Note that email clients will use the last supported part/alternative view, so the text version should always be added first.

Carter answered 2/8, 2023 at 20:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.