13

I have some images stored in the Resources.resx file in my solution. I would like to use these images in my email. I have loaded the image into a variable:

Bitmap myImage = new Bitmap(Resources.Image);

and now I want to put it in the HTML in the AlternateView string I am using to create the HTML email. Just need some help.

Here is the HTML string(partial):

 body += "</HEAD><BODY><DIV style='height:100%; width:700px;'><div style='height:70px; width:700px; background-color:red;'><img src='" + myImage + "' width='104' height='27' alt='img' style='margin: 20px 0px 0px 20px;'/></div>

Any help would be greatly appreciated Thanks!

EDIT: Here is the entire Code block. I think I am close to getting it, just inexperience getting in the way here :) I tried converting it into a Byte like suggested which got me farther. Still not rendering the image. There is something here I am not doing right. Thank you so much for all of you help everyone! Here is the code (the HTML I need for the image is in the 3 line of the string body = code):

 if (emailTo != null)
        {

            Bitmap myImage = new Bitmap(Resources.comcastHeader);
            ImageConverter ic = new ImageConverter();
            Byte[] ba = (Byte[])ic.ConvertTo(myImage, typeof(Byte[]));
            MemoryStream image1 = new MemoryStream(ba);

            LinkedResource headerImage = new LinkedResource(image1, "image/jpeg");
            headerImage.ContentId = "companyLogo";


            System.Net.Mail.MailMessage message = new System.Net.Mail.MailMessage();
            message.To.Add("" + emailTo + "");
            message.Subject = "" + customer + " Your order is being processed...";
            message.From = new System.Net.Mail.MailAddress("noreply@stormcopper.com");



            string body = "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">";
            body += "<HTML><HEAD><META http-equiv=Content-Type content=\"text/html; charset=iso-8859-1\">";
            body += "</HEAD><BODY><DIV style='height:100%; width:700px;'><div style='height:70px; width:700px; background-color:red;'><img src=\"cid:companyLogo\" width='104' height='27' alt='img' style='margin: 20px 0px 0px 20px;'/></div><P>Hello " + customer + ",</P><P>Thank you for shopping at <a href='" + store + "'>" + store + "</A>.  Your order is being processed and will be shipped to you soon.  We would like to take this time to thank you for choosing Storm Copper Components, and we hope you are completely satisfied with your purchase. Please review your information and make sure all the information is correct.  If there are any errors in your order, please contact us immediately <A href='mailto:busbar@stormcopper.com'>here.</A></P>";               
            body += "<P><B>Here is your order information:</B></P>";
            body += "<H3>Contact Information</H3><TABLE><TR><TD><B>Name:</B> " + customer + "</TR></TD><TR><TD><B>Address:</B> " + street + " " + city + ", " + state + " " + zip + "</TR></TD><TR><TD><B>Email:</B> " + emailTo + "</TR></TD><TR><TD><B>Phone:</B> " + phone + "</TR></TD><TR><TD></TD></TR></TABLE>";
            body += "<H3>Products Ordered</H3><TABLE>" + productInformation + "</TABLE><BR /><BR />";
            body += "<H3>Pricing Information</H3><TABLE><TR><TD>Subtotal: $" + subTotal + "</TD></TR><TR><TD>Shipping: $" + shippingInfo + " </TD></TR><TR><TD>Tax: $" + taxInfo + "</TD></TR><TR><TD><B>Total:</B> $" + total + "</TD></TR><BR /></TABLE>";
            body += "<P>Thank you for shopping with us!</P><A href='stormcopper.com'>Storm Copper Components</A>";
            body += "<P><I>This is an Auto-Generated email sent by store copper.  Your email will not be sent to Storm Copper Components if you reply to this message.  If you need to change any information, or have any questions about your order, please contact us using the information provided in this email.</I></P></DIV></BODY></HTML>";



            ContentType mimeType = new System.Net.Mime.ContentType("text/html");

            AlternateView alternate = AlternateView.CreateAlternateViewFromString(body, mimeType);

            message.AlternateViews.Add(alternate);
            System.Net.Mail.SmtpClient smtp = new System.Net.Mail.SmtpClient("########");
            smtp.Send(message);

        }
lazoDev
  • 349
  • 1
  • 4
  • 19

5 Answers5

26

you need to add them in the email message as CID's/linked resources.

here is some code I have used before which works nicely. I hope this gives you some guidance:

Create an AlternateView:

AlternateView av = AlternateView.CreateAlternateViewFromString(body, null, isHTML ? System.Net.Mime.MediaTypeNames.Text.Html : System.Net.Mime.MediaTypeNames.Text.Plain)

Create a Linked Resource:

LinkedResource logo = new LinkedResource("SomeRandomValue", System.Net.Mime.MediaTypeNames.Image.Jpeg);
logo.ContentId = currentLinkedResource.Key;
logo.ContentType = new System.Net.Mime.ContentType("image/jpg");

// add it to the alternative view

av.LinkedResources.Add(logo);

// finally, add the alternative view to the message:

msg.AlternateView.Add(av);

here is some documentation to help you with what the AlternativeView and LinkedResources are and how it works:

http://msdn.microsoft.com/en-us/library/system.net.mail.mailmessage.alternateviews(v=vs.110).aspx http://msdn.microsoft.com/en-us/library/system.net.mail.linkedresource(v=vs.110).aspx http://msdn.microsoft.com/en-us/library/ms144669(v=vs.110).aspx

in the HTML itself, you need to do something like the following:

"<img style=\"width: 157px; height: 60px;\" alt=\"blah blah\" title=\"my title here\" src=\"cid:{0}\" />";

notice the CID followed by a string format {0} - I then use this to replace it with a random value.

UPDATE

To go back and comment on the posters comments... here is the working solution for the poster:

string body = "blah blah blah... body goes here with the image tag: <img src=\"cid:companyLogo\" width="104" height="27" />";

byte[] reader = File.ReadAllBytes("E:\\TestImage.jpg");
MemoryStream image1 = new MemoryStream(reader);
AlternateView av = AlternateView.CreateAlternateViewFromString(body, null, System.Net.Mime.MediaTypeNames.Text.Html);

LinkedResource headerImage = new LinkedResource(image1, System.Net.Mime.MediaTypeNames.Image.Jpeg);
headerImage.ContentId = "companyLogo";
headerImage.ContentType = new ContentType("image/jpg");
av.LinkedResources.Add(headerImage);


System.Net.Mail.MailMessage message = new System.Net.Mail.MailMessage();
message.AlternateViews.Add(av);
message.To.Add(emailTo);
message.Subject = " Your order is being processed...";
message.From = new System.Net.Mail.MailAddress("xxx@example.com");


ContentType mimeType = new System.Net.Mime.ContentType("text/html");
AlternateView alternate = AlternateView.CreateAlternateViewFromString(body, mimeType);
message.AlternateViews.Add(alternate);

// then send message!

Maytham Fahmi
  • 31,138
  • 14
  • 118
  • 137
Ahmed ilyas
  • 5,722
  • 8
  • 44
  • 72
  • Edit: I am using the AlternateView to create the email. I believe this to be the right answer I am just not doing it right :) Right now, I have the images stored in the myPro.Properties.Resources area. Should they just be in a regular folder in the solution? Do they need to be embedded resources as well? The way the images are rendering right now is as a bitmap. I do not see any ID reference I can use to populate the ContentID of the Linked Resource. – lazoDev Nov 11 '13 at 17:10
  • They should be on disk so it can then take it and do what it needs to do (i.e convert to bytes for the email attachment). This is actually the parameter requirement on the LinkedResource object. – Ahmed ilyas Nov 11 '13 at 17:45
  • I updated my code here and placed the entire code block in if you would not mind taking a look. Thanks you. I think I am on the right path here. – lazoDev Nov 11 '13 at 19:42
  • I got it you were right. I did need to convert it to a Byte first before I could use it as a LinkedResource. Also had to add it to the alternate view alternate.LinkedResources.Add(hearderImage); – lazoDev Nov 11 '13 at 19:51
  • 1
    I updated my posted for your solution. but sounds like you are on your way now. – Ahmed ilyas Nov 11 '13 at 20:13
  • note: AlternateView, LinkedResource, and MailMessage are not managed. They must be disposed. – tdbeckett Jun 25 '15 at 19:00
  • 6
    What is the point of creating av and then after that alternate? They appear to be the same? – tdbeckett Jun 25 '15 at 19:28
  • 1
    @tdbeckett I think it's a bad implementation of this advice : https://stackoverflow.com/questions/1212838/c-sharp-sending-mails-with-images-inline-using-smtpclient One should send the 2 Alternate Views, one in html, one in plain text for older/lighter mail clients – Poutrathor Jun 04 '18 at 15:11
  • Take care of the encoding of the html AlternateView, it should be defined to prevent issues with special characters. e.g. `AlternateView.CreateAlternateViewFromString(body, Encoding.UTF8, MediaTypeNames.Text.Html);` – Benjamin Freitag Jan 10 '23 at 12:42
1

One option is put the image in one host, and in the src put the url, like this "src='http://www.host/myImage.jpg'" This way you do not have to load the image in each mail and would be more agile.

Nacho
  • 1,023
  • 1
  • 10
  • 26
  • 2
    Most email servers will block this and tag it as a potential threat. This email is getting sent from the server as well, so the image should come from here as an embedded file. I do not want this email to go to a junk file. Thanks for the response. :) – lazoDev Nov 11 '13 at 16:55
1

If it helps anyone, here is a version based on Ahmed ilyas' very useful answer, which passes the actual Bitmap to the memory stream, and encloses the various objects which implement IDisposable in using blocks -

public void SendMailExample(string emailAddressTo, string hexColour)
    {
        // Give the LinkedResource an ID which should be passed into the 'cid' of the <img> tag -
        var linkedResourceId = "mylogo";
        var sb = new StringBuilder("");
        sb.Append("<body><p>This is the HTML email body with img tag...<br /><br />");
        sb.Append($"<img src=\"cid:{linkedResourceId}\" width=\"100\" height=\"115.5\" alt=\"Logo\"/>");
        sb.Append("<p></body>");
        var emailBodyHtml = sb.ToString();
        var emailBodyPlain = "This is the plain text email body";

        using (var message = new MailMessage())
        using (var logoMemStream = new MemoryStream())
        using (var altViewHtml = AlternateView.CreateAlternateViewFromString(emailBodyHtml, null, System.Net.Mime.MediaTypeNames.Text.Html))
        using (var altViewPlainText = AlternateView.CreateAlternateViewFromString(emailBodyPlain, null, System.Net.Mime.MediaTypeNames.Text.Plain))
        using (var client = new System.Net.Mail.SmtpClient(_smtpServer)
        {
            Port = 25,
            DeliveryMethod = System.Net.Mail.SmtpDeliveryMethod.Network,
            UseDefaultCredentials = false,
            EnableSsl = false
        })
        {
            message.To.Add(emailAddressTo);
            message.From = new MailAddress(_emailAddressFrom);
            message.Subject = "This is the email subject";

            // Assume that GetLogo() just returns a Bitmap (for my particular problem I had to return a logo in a specified colour, hence the hexColour parameter!)
            Bitmap logoBitmap = GetLogo(hexColour);
            logoBitmap.Save(logoMemStream, System.Drawing.Imaging.ImageFormat.Png);
            logoMemStream.Position = 0;

            using (LinkedResource logoLinkedResource = new LinkedResource(logoMemStream))
            {
                logoLinkedResource.ContentId = linkedResourceId;
                logoLinkedResource.ContentType = new ContentType("image/png");
                altViewHtml.LinkedResources.Add(logoLinkedResource);
                message.AlternateViews.Add(altViewHtml);
                message.AlternateViews.Add(altViewPlainText);

                client.Send(message);
            }
        }
    }
Parrybird
  • 800
  • 11
  • 18
0

I know this is an old post, but if someone still hits this looking for an answer (like I did), then I have a simpler answer.

You can use a simple overload of LinkedResource object that directly takes the file path as the parameter. So there is no need to explicitly load image into memory stream. Of course, this example assumes you have access to the image on the disk -

Here is the complete function code which worked for me -

public System.Net.Mail.AlternateView GetAlternateView(string MessageText, string LogoPath, bool bSilent)
{

    try
    {
        MessageText += "<br><img title='' alt='' src='cid:SystemEmail_HTMLLogoPath' />";               

        System.Net.Mail.AlternateView view = System.Net.Mail.AlternateView.CreateAlternateViewFromString(MessageText, null, "text/html");
        System.Net.Mail.LinkedResource linked = new System.Net.Mail.LinkedResource(HttpContext.Current.Request.PhysicalApplicationPath + LogoPath);
        linked.ContentId = "SystemEmail_HTMLLogoPath";
        view.LinkedResources.Add(linked);
        return view;
    }
    catch (Exception ex)
    {
        if (bSilent)
            return null;
        else
            throw ex;
    }
}
AV2000
  • 459
  • 5
  • 5
-2

you should not assign the Bitmap object to <img> tag as it expects the image path.
Replace this:

body += "</HEAD><BODY><DIV style='height:100%; width:700px;'><div style='height:70px; width:700px; background-color:red;'><img src='" + myImage + "' width='104' height='27' alt='img' style='margin: 20px 0px 0px 20px;'/></div>

With following :

body += "</HEAD><BODY><DIV style='height:100%; width:700px;'><div style='height:70px; width:700px; background-color:red;'><img src='" + Resources.Image+ "' width='104' height='27' alt='img' style='margin: 20px 0px 0px 20px;'/></div>
Sudhakar Tillapudi
  • 25,935
  • 5
  • 37
  • 67