Convert MSG email to PDF file in C#

Viewed 5080

I'm using GemBox.Email and GemBox.Document to convert emails to PDF.

This is my code:

static void Main()
{
    MailMessage message = MailMessage.Load("input.eml");
    DocumentModel document = new DocumentModel();

    if (!string.IsNullOrEmpty(message.BodyHtml))
        document.Content.LoadText(message.BodyHtml, LoadOptions.HtmlDefault);
    else
        document.Content.LoadText(message.BodyText, LoadOptions.TxtDefault);

    document.Save("output.pdf");
}

The code works for EML files, but it doesn't for MSG (both MailMessage.BodyHtml and MailMessage.BodyText) are empty.

How can I make this work for MSG as well?

1 Answers

The problem occurs with specific MSG files that don't have HTML content within an RTF body, instead, they have raw RTF body.

The MailMessage class currently doesn't expose API for the RTF body (only plain and HTML body). Nevertheless, you can retrieve it as an Attachment named "Body.rtf".

Also as an FYI, another problem you have is that the images from the email's HTML body are not inlined, and thus, you'll lose them when exporting to PDF.

Anyway, try using the following:

static void Main()
{
    // Load an email (or retrieve it with POP or IMAP).
    MailMessage message = MailMessage.Load("input.msg");

    // Create a new document.
    DocumentModel document = new DocumentModel();

    // Import the email's body to the document.
    LoadBody(message, document);

    // Save the document as PDF.
    document.Save("output.pdf");
}

static void LoadBody(MailMessage message, DocumentModel document)
{
    if (!string.IsNullOrEmpty(message.BodyHtml))
    {
        var htmlOptions = LoadOptions.HtmlDefault;
        // Replace attached CID images to inlined DATA urls.
        var htmlBody = ReplaceEmbeddedImages(message.BodyHtml, message.Attachments);
        // Load HTML body to the document.
        document.Content.End.LoadText(htmlBody, htmlOptions);
    }
    else if (message.Attachments.Any(a => a.FileName == "Body.rtf"))
    {
        var rtfAttachment = message.Attachments.First(a => a.FileName == "Body.rtf");
        var rtfOptions = LoadOptions.RtfDefault;
        // Get RTF body from the attachment.
        var rtfBody = rtfOptions.Encoding.GetString(rtfAttachment.Data.ToArray());
        // Load RTF body to the document.
        document.Content.End.LoadText(rtfBody, rtfOptions);
    }
    else
    {
        // Load TXT body to the document.
        document.Content.End.LoadText(message.BodyText, LoadOptions.TxtDefault);
    }
}

static string ReplaceEmbeddedImages(string htmlBody, AttachmentCollection attachments)
{
    var srcPattern =
        "(?<=<img.+?src=[\"'])" +
        "(.+?)" +
        "(?=[\"'].*?>)";

    // Iterate through the "src" attributes from HTML images in reverse order.
    foreach (var match in Regex.Matches(htmlBody, srcPattern, RegexOptions.IgnoreCase).Cast<Match>().Reverse())
    {
        var imageId = match.Value.Replace("cid:", "");
        Attachment attachment = attachments.FirstOrDefault(a => a.ContentId == imageId);

        if (attachment != null)
        {
            // Create inlined image data. E.g. "data:image/png;base64,AABBCC..."
            ContentEntity entity = attachment.MimeEntity;
            var embeddedImage = entity.Charset.GetString(entity.Content);
            var embeddedSrc = $"data:{entity.ContentType};{entity.TransferEncoding},{embeddedImage}";

            // Replace the "src" attribute with the inlined image.
            htmlBody = $"{htmlBody.Substring(0, match.Index)}{embeddedSrc}{htmlBody.Substring(match.Index + match.Length)}";
        }
    }

    return htmlBody;
}

For more information (like how to add email headers and attachments to output PDF), check the Convert Email to PDF examples.

Related