12

I'm starting with SendGrid to send my e-mails, but I coudn't find how to embed images. Without using SendGrid I was using the following code to send e-mails with embedded images:

var mail = new System.Net.Mail.MailMessage();
mail.Subject = "Warning";
mail.From = "from_user@test.com";
mail.To.Add("to_user@test.com");
mail.IsBodyHtml = true;
mail.Body = "<html><body><a href='http://www.mywebsite.com' title='My Website'><img src='cid:my_image' alt='My Image' border='0' /></a><br /><h1>My E-mail Title</h1>E-mail content.</body></html>";
var av = AlternateView.CreateAlternateViewFromString(mail.Body, null, "text/html");
av.LinkedResources.Add(new LinkedResource(@"C:\my_image.png", "image/png"){ContentId="my_image"});
mail.AlternateViews.Add(av);
var smtp = new SmtpClient("smtp.test.com");
smtp.Credentials = new NetworkCredential("user", "pass");
smtp.Send(mail);

--- EDITED ---

Now I'm using the following code to send my e-mails (using SendGrid classes).

var message = SendGrid.GetInstance();
message.Subject = "Warning";
message.From = new MailAddress("from_user@test.com");
message.To = new MailAddress[] { new MailAddress("to_user@test.com") };
message.Html = "<html><body><a href='http://www.mywebsite.com' title='My Website'><img src='cid:my_image' alt='My Image' border='0' /></a><br /><h1>My E-mail Title</h1>E-mail content.</body></html>";
var transportSMTP = SMTP.GetInstance(new NetworkCredential("user", "pass"));
transportSMTP.Deliver(message);

What I need to know is how to embed and link my images inside the e-mail using its content id (CID).

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
Diogo Arenhart
  • 407
  • 3
  • 8
  • 15
  • Could you show us the code you're using **now**? – Swift Apr 01 '13 at 23:22
  • And why couldn't you use the same code? – Swift Apr 01 '13 at 23:23
  • I've added the code I'm using now. To send e-mails with sendgrid I'm using their own classes. Here's a link to download: https://github.com/sendgrid/sendgrid-csharp. May I use default .net classes to send mails with sendgrid? – Diogo Arenhart Apr 02 '13 at 12:24
  • 1
    Yes, you could use the default .net classes for sending emails. Just configure it to point at `smtp.sendgrid.net`. The only time you would really want to use the SendGrid library is if you're making extensive use of the X-SMTPAPI header, which the library makes a lot easier – Swift Apr 02 '13 at 17:23
  • I am having the same issue. Using SendGrid api to send emails so that I can embed unique arguments and cannot figure out how to embed images. Has anyone gotten this to work using the C# wrapper: github.com/sendgrid/sendgrid-csharp – user327999 Dec 05 '14 at 22:54
  • Is this not possible with the c# library? – TWilly Jan 23 '15 at 22:42

4 Answers4

7

I juggled around this for a little bit too. The solution was to Attach the image first and then to Embed afterwards with the direct name of the file in the email.

var myMessage = new SendGridMessage();
myMessage.AddTo("to@email.com");
myMessage.From = "from@email.com";
myMessage.Subject ="Forgotten Password";
string body = @"<div><img src='cid:email_reset' alt='Email Reset Header' border='0' /></div>" +
              @"<p>Content...</p>";

string att = Request.PhysicalApplicationPath + @"Content\files\images\email_reset.jpg";
var attachment = new Attachment(att, new ContentType("image/jpeg"));
var linkedResource = new LinkedResource(att, new ContentType("image/jpeg"));
myMessage.AddAttachment(attachment.ContentStream, attachment.Name);
myMessage.EmbedImage(attachment.Name, "email_reset");

myMessage.Text = WebUtility.HtmlDecode(Regex.Replace(body, "<[^>]*(>|$)", string.Empty));
myMessage.Html = body;

// Authenticate and Send the email
phillihp
  • 628
  • 8
  • 10
3

For anyone who is struggling with sending embedded images in the emails via SendGrid and using the stored templates, here's how it works:

/* In my case the images reside in the SQL DB as BLOBs but for this example it does not matter.
All you need is an array of bytes with your image.
*/
var imageContent = File.ReadAllBytes("Images\\logo_eml.jpg");
using (MemoryStream s = new MemoryStream(imageContent))
{
    ContentType ctype = new ContentType("image/jpg");
    var attachment = new System.Net.Mail.Attachment(s, ctype);
    var linkedResource = new LinkedResource(s, ctype);
    attachment.Name = "cibc_ins_logo_eml.jpg";
    emailMsg.AddAttachment(attachment.ContentStream, attachment.Name);
    emailMsg.EmbedImage(attachment.Name, linkedResource.ContentId + ".jpg");

    values.Add("%embedLogo%", linkedResource.ContentId + ".jpg");
}

string templateJSON = "{\"to\": [\"%to%\"],\r \"sub\": {\":name\": [\"%name%\"],\":embedLogo\": [\"%embedLogo%\"]},\r \"category\": [\"Quotes\"],\r \"filters\": {\"templates\": {\"settings\": {\"enable\": 1,\"template_id\": \"%templateid%\"}}}}"
emailMsg.Headers.Add("x-smtpapi", SubstituteTemplate(templateJSON, values));

The last line will replace the values. In my case it simply does a regex replace. This code will have to take care of substituting %embedLogo% in your particular JSON with the value of linkedResource.ContentId+".jpg" stored previously in the values which is a Dictionary<string,string>.

Here's what you need in the stored HTML template:

<img width="227" height="86" src="cid::embedLogo">

CID and two colons are critical.

Then Gmail will show the images embedded and not just attached!

ajeh
  • 2,652
  • 2
  • 34
  • 65
2

I talked with a SendGrid customer support engineer and he directed me here..

https://github.com/sendgrid/sendgrid-csharp/blob/ca91fad22dfec2cd1219267fe979c1d9a33a522e/SendGrid/SendGridMail/SendGrid.cs#L211

So your code would be...

var message = SendGrid.GetInstance();
message.Subject = "Warning";
message.From = new MailAddress("from_user@test.com");
message.To = new MailAddress[] { new MailAddress("to_user@test.com") };
message.Html = "<html><body><a href='http://www.mywebsite.com' title='My Website'><img src='cid:my_image' alt='My Image' border='0' /></a><br /><h1>My E-mail Title</h1>E-mail content.</body></html>";

// added    
message.EmbedImage(@"C:\my_image.png","my_image");
// added

var transportSMTP = SMTP.GetInstance(new NetworkCredential("user", "pass"));
transportSMTP.Deliver(message);

I'm looking for a way to add a MemoryStream object instead of a filename, which it doesn't look like this is available yet.

TWilly
  • 4,863
  • 3
  • 43
  • 73
  • Actually, it is. Take a look at this anser from a similar question: http://stackoverflow.com/a/27362265/292230 . You can instantiate LinkedResource with a MemoryStream instead of a filename. – Prutswonder Apr 22 '15 at 12:36
  • I am using `MemoryStream` to load the images from DB, but not using `EmbedImage` and the attached images work fine in Outlook but not in Gmail. I tried all kinds of `EmbedImage()` calls to no avail - Outlook always works, Gmail never does. I am ready to jump out of the window. – ajeh Jan 25 '17 at 21:43
1

For anyone looking for something simpler, you can encode the image file in Base64 and then directly embbed it as a String into the html body of the email, it worked for me as I just wanted to include a small logo in the email signature:

<img alt="My Image" src="data:image/jpeg;base64,/9j/4S/+RXhpZgAATU0AKgAAAAgACAESAAMAENkDZ5u8/61a+X...more encoding" />
Osmar
  • 557
  • 6
  • 10