I want to send mails with images in them. The code I've written works fine, but for some reason unknown to me it wont work with Outlook clients. The test mail I sent was (left: Thunderbird, right: Outlook):
What my code is supposed to do is: It takes the RTF from a RichTextBox
and converts it to HTML. This leaves the images embedded in the HTML as base64 strings. I extract all base64 encoded images one by one and put them into a MemoryStream
which is accepted by LinkedResource
. Since mail clients usually don't accept embedded images I replace the embedded image in the HTML with a content-id. Then I set some properties of LinkedResource
and add it to an AlternateView
. This alternate view is then added to a System.Net.Mail.MailMessage
and the mail is sent.
The corresponding code:
MemoryStream mem = null;
private readonly Regex embeddedImageRegex = new Regex("src=\"data:image/.*?\"");
public MyHTMLMailMessage()
: base()
{
this.SubjectEncoding = Encoding.UTF8;
this.BodyEncoding = Encoding.UTF8;
this.IsBodyHtml = true;
}
public bool Send()
{
// create HTML View with images
AlternateView htmlView = AlternateView.CreateAlternateViewFromString(HTML, System.Text.Encoding.UTF8, MediaTypeNames.Text.Html);
ReplaceEmbeddedImagesWithCID(htmlView);
this.AlternateViews.Add(htmlView);
this.Body = HTML;
SmtpClient client = new SmtpClient(server, port);
client.DeliveryMethod = SmtpDeliveryMethod.Network;
client.UseDefaultCredentials = String.IsNullOrEmpty(username);
try
{
client.Send(this);
return true;
}
catch (SmtpException e)
{
return false;
}
finally
{
mem?.Close();
}
}
private void ReplaceEmbeddedImagesWithCID(AlternateView altView)
{
string extension;
int imageIndex = 0;
string contentID = $"image{imageIndex}";
// go through every base64 string, create a content id and LinkedResource for it
while (embeddedImageRegex.IsMatch(HTML))
{
extension = new Regex("image/.*?;").Match(HTML).Value
.Replace("image/", "")
.Replace(";", "");
string base64img = embeddedImageRegex.Match(HTML).Value
.Replace("src=\"", "")
.Replace("\"", "")
.Split(',')[1];
HTML = embeddedImageRegex.Replace(HTML, $"src=\"cid:image{imageIndex}\"", 1);
byte[] byBitmap = Convert.FromBase64String(base64img);
mem = new MemoryStream(byBitmap);
mem.Position = 0;
LinkedResource linkedImage = new LinkedResource(mem, $"image/{extension}");
linkedImage.ContentId = contentID;
altView.LinkedResources.Add(linkedImage);
altView = AlternateView.CreateAlternateViewFromString(HTML, null, MediaTypeNames.Text.Html);
imageIndex++;
}
}
So I went through different solutions but none of them worked. My steps so far:
I edited some registration keys in
HKEY_CURRENT_USER\SOFTWARE\Microsoft\Office\x.0\Outlook\Options\Mail
orHKEY_CURRENT_USER\SOFTWARE\Microsoft\Office\x.0\Common
I left the image as base64 string in the HTML
There were some properties added
linkedImage.TransferEncoding = TransferEncoding.Base64;
linkedImage.ContentType.Name = contentID;
linkedImage.ContentLink = new Uri($"cid:{contentID}");
this.Headers.Add("Content-ID", $"<image{imageIndex}>");
this.Headers.Add("X-Attachment-Id", $"image{imageIndex}");
altView.TransferEncoding = TransferEncoding.QuotedPrintable;
None of this worked for me even although it seemed to help others. Did i overlook something?