Search code examples
c#htmlimageoutlookmailmessage

(C#) Image in Mail not displayed in Outlook


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):

Mail as seen in a Thunderbird client Mail as seen in an Outlook client

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:

  1. I edited some registration keys in HKEY_CURRENT_USER\SOFTWARE\Microsoft\Office\x.0\Outlook\Options\Mail or HKEY_CURRENT_USER\SOFTWARE\Microsoft\Office\x.0\Common

  2. I left the image as base64 string in the HTML

  3. 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?


Solution

  • Base64 images are blocked by default in Outlook.

    You need to attach images to the email and set the PR_ATTACH_CONTENT_ID property on the email (the DASL name is "http://schemas.microsoft.com/mapi/proptag/0x3712001E"). See Embed Images in New Messages using a Macro for more information.