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);
fluf
  • 1,261
  • 2
  • 22
  • 36
  • where does "head" come from, and what do you do with "foot"? – Massif Jun 07 '11 at 08:33
  • 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. – fluf Jun 07 '11 at 09:49

6 Answers6

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.

fluf
  • 1,261
  • 2
  • 22
  • 36
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;
Jeremy
  • 289
  • 3
  • 5
  • 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! @Jeremy Thanks so much :-) – Xan-Kun Clark-Davis Mar 16 '17 at 22:41
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.

Tee
  • 81
  • 4
  • 2
    Unfortunately some webmail clients don't work too well with base64 embedded images. See https://stackoverflow.com/questions/3279523/base64-images-to-gmail – Vinzz Feb 24 '20 at 15:55
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);
Eric
  • 1
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("me@mycompany.com");
   mail.To.Add("you@yourcompany.com");
   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);
}
splattne
  • 102,760
  • 52
  • 202
  • 249
danyolgiax
  • 12,798
  • 10
  • 65
  • 116
  • 1
    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 -> LinkedResource – fluf Jun 07 '11 at 07:53
  • 4
    He asked about to use `Bitmap` and `MemoryStream` and not the direct image file... – NoWar May 09 '13 at 15:07
  • Watch out - `MailMessage` and `SmtpClient` implement `IDisposable` so should be in a `using` statement or disposed manually. – dav_i Jun 23 '14 at 15:54
  • This isn't related the the OPs question. – Dan Cundy Jul 01 '20 at 16:10
  • 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? – Tiger Galo Jul 27 '20 at 18:34
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.

Davak72
  • 66
  • 5