My .NET 4.5 web application uses class SmtpClient to create and send e-mail messages to various recipients. Each e-mail message consists of:

  • an HTML message body
  • an embedded inline image (JPeg or PNG or GIF)
  • an attachment (PDF)

Sample code is below. It works fine, but there is one gripe from OSX users. Apple's standard mail app renders the image twice; once inlined in the message body, and again following the message body, next to the preview of the PDF attachment.


Screenshot Apple Mail, faulty message


I tinkered with the following properties; none of which would help.

  • SmtpClient's DeliveryFormat
  • MailMessage's IsBodyHtml and BodyTransferEncoding
  • Attachment's MimeType, Inline, DispositionType, ContentId, FileName, Size, CreationDate, ModificationDate

If I compose a similar e-mail message in MS Outlook and send it off to the Apple user, the image is rendered once, inlined in the message body; exactly as I would like it to be. So apparently it is possible. After reading this, I inspected the raw MIME data, and noticed Outlook uses multipart/related to group together the message body and the images.


Screenshot Apple Mail, message from Outlook


My question: How do I mimic Outlook's behavior with the classes found in System.Net.Mail?

Things I would rather not do:

  • Employ external images instead of embedded ones (many e-mail clients initially block these to protect recipient's privacy).
  • Use third party libraries (to avoid legal hassle). The SmtpDirect class I found here seems to solve the problem (though I got a server exception in return), but it is hard for me to accept a complete rewrite of MS's SmtpClient implementation is necessary for such a subtle change.
  • Send the e-mail message to a pickup folder, manipulate the resulting .eml file, push the file to our Exchange server.

Minimal code to reproduce the problem:

using System.IO;
using System.Net.Mail;
using System.Net.Mime;

namespace SendMail
{
    class Program
    {
        const string body = "Body text <img src=\"cid:ampersand.gif\" /> image.";

        static Attachment CreateGif()
        {
            var att = new Attachment(new MemoryStream(Resource1.ampersand), "ampersand.gif")
            {
                ContentId = "ampersand.gif",
                ContentType = new ContentType(MediaTypeNames.Image.Gif)
            };
            att.ContentDisposition.Inline = true;
            return att;
        }

        static Attachment CreatePdf()
        {
            var att = new Attachment(new MemoryStream(Resource1.Hello), "Hello.pdf")
            {
                ContentId = "Hello.pdf",
                ContentType = new ContentType(MediaTypeNames.Application.Pdf)
            };
            att.ContentDisposition.Inline = false;
            return att;
        }

        static MailMessage CreateMessage()
        {
            var msg = new MailMessage(Resource1.from, Resource1.to, "The subject", body)
            {
                IsBodyHtml = true
            };
            msg.Attachments.Add(CreateGif());
            msg.Attachments.Add(CreatePdf());
            return msg;
        }

        static void Main(string[] args)
        {
            new SmtpClient(Resource1.host).Send(CreateMessage());
        }
    }
}

To actually build and run it, you will need an additional resource file Resource1.resx with the two attachments (ampersand and Hello) and three strings host (the SMTP server), from and to (both of which are e-mail addresses).

Related posts

Recent Viewed