简体   繁体   中英

How to use OpenPop to read e-mail as HTML?

We use OpenPop to get e-mails. I have to read the subject of the message and show it to the user. When the user clicks on the message, I want to show the content of the message in a placeholder.
Here is my code to show the content but it is not working very well:

plhMessage.Controls.Add(new LiteralControl(Encoding.UTF8.GetString(client.GetMessage(0).RawMessage)));

It returns this text on head:

Return-Path: Bounce@adspackages.com 
Received: from adspackages.com (Unknown [185.81.96.156]) by ip-30.afaghhost.com ; Mon, 7 Mar 2016 07:13:06 +0330 
DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=adspackages.com; 
    s=default; h=Content-Transfer-Encoding:Content-Type: 
    MIME-Version:Message-ID:Subject:Reply-To:From:To:Date;
    bh=MBNWLlH5FJIZMrbe+SG0izGjV9d9fR6eupDkfvgklSw=; 
    b=DLYlNuMd7ZAPCpQTQvGCi7yBiX aRhjlqQ8zGLPWcmDDX159frMVPiTh652Os3xwxWZ/iS4BQeOA5cFXdZSwcCxIO9hEaGr7ogZXVM5k blpgoO3htf9GAPJSDOxxVWIjEYgN3+m7UE1N7azmtvUPrrZkl9H8JwCIXLbI0SRpmHQ2ebA7QMgQM /Jl8u+5dLmWo4eYLxFgyTjZwTPPmLKwfSADjET3bb9ZfBTcK/KHsAjfx7Miy7zgP5vSE1n+p ....

and show the message without the pictures.

How can I get the HTML of the e-mail to show it in a placeholder? Also, how can I show the pictures contained in the e-mail?

Before I begin, I should note that you cannot use Encoding.UTF8.GetBytes() on client.GetMessage(0).RawMessage reliably because that (wrongly) assumes that the raw message data is in UTF-8 and that is not guaranteed to be the case. Most emails in Western Europe will be in one of the Latin encodings, Russian emails will typically be in iso-8859-5, windows-1251 or koi8-r. Chinese, Japanese and Korean email will almost always be in one of their locale charsets (usually gbk/big5, iso-2022-jp, and euc-kr respectively).

Now that that is settled... let's move on to your main question.

What you want to do is quite frankly a lot easier to do using MailKit than it is using OpenPOP, so I'll show you how to do it using MailKit instead:

To get the message, MailKit works very much like OpenPOP does:

using System;

using MailKit.Net.Pop3;
using MailKit;
using MimeKit;

namespace TestClient {
    class Program
    {
        public static void Main (string[] args)
        {
            using (var client = new Pop3Client ()) {
                client.Connect ("pop.gmail.com", 995, true);

                // Note: since we don't have an OAuth2 token, disable
                // the XOAUTH2 authentication mechanism.
                client.AuthenticationMechanisms.Remove ("XOAUTH2");

                client.Authenticate ("user.name@gmail.com", "password");

                for (int i = 0; i < client.Count; i++) {
                    var message = client.GetMessage (i);
                    // TODO: render the message
                }

                client.Disconnect (true);
            }
        }
    }
}

To render a message using MailKit, the easiest way is to write your own MimeVisitor like this:

/// <summary>
/// Visits a MimeMessage and generates HTML suitable to be rendered by a browser control.
/// </summary>
class HtmlPreviewVisitor : MimeVisitor
{
    List<MultipartRelated> stack = new List<MultipartRelated> ();
    List<MimeEntity> attachments = new List<MimeEntity> ();
    string body;

    /// <summary>
    /// Creates a new HtmlPreviewVisitor.
    /// </summary>
    public HtmlPreviewVisitor ()
    {
    }

    /// <summary>
    /// The list of attachments that were in the MimeMessage.
    /// </summary>
    public IList<MimeEntity> Attachments {
        get { return attachments; }
    }

    /// <summary>
    /// The HTML string that can be set on the BrowserControl.
    /// </summary>
    public string HtmlBody {
        get { return body ?? string.Empty; }
    }

    protected override void VisitMultipartAlternative (MultipartAlternative alternative)
    {
        // walk the multipart/alternative children backwards from greatest level of faithfulness to the least faithful
        for (int i = alternative.Count - 1; i >= 0 && body == null; i--)
            alternative[i].Accept (this);
    }

    protected override void VisitMultipartRelated (MultipartRelated related)
    {
        var root = related.Root;

        // push this multipart/related onto our stack
        stack.Add (related);

        // visit the root document
        root.Accept (this);

        // pop this multipart/related off our stack
        stack.RemoveAt (stack.Count - 1);
    }

    // look up the image based on the img src url within our multipart/related stack
    bool TryGetImage (string url, out MimePart image)
    {
        UriKind kind;
        int index;
        Uri uri;

        if (Uri.IsWellFormedUriString (url, UriKind.Absolute))
            kind = UriKind.Absolute;
        else if (Uri.IsWellFormedUriString (url, UriKind.Relative))
            kind = UriKind.Relative;
        else
            kind = UriKind.RelativeOrAbsolute;

        try {
            uri = new Uri (url, kind);
        } catch {
            image = null;
            return false;
        }

        for (int i = stack.Count - 1; i >= 0; i--) {
            if ((index = stack[i].IndexOf (uri)) == -1)
                continue;

            image = stack[i][index] as MimePart;
            return image != null;
        }

        image = null;

        return false;
    }

    // Save the image to our temp directory and return a "data:" url suitable for
    // the browser control to load.
    string GetDataImageSrc (MimePart image)
    {
        using (var output = new MemoryStream ()) {
            image.ContentObject.DecodeTo (output);
            return string.Format ("data:{0};base64,{1}", image.ContentType.MimeType, Convert.ToBase64String (output.GetBuffer (), 0, (int) output.Length));
        }
    }

    // Replaces <img src=...> urls that refer to images embedded within the message with
    // "data:" urls that the browser control will actually be able to load.
    void HtmlTagCallback (HtmlTagContext ctx, HtmlWriter htmlWriter)
    {
        if (ctx.TagId == HtmlTagId.Image && !ctx.IsEndTag && stack.Count > 0) {
            ctx.WriteTag (htmlWriter, false);

            // replace the src attribute with a file:// URL
            foreach (var attribute in ctx.Attributes) {
                if (attribute.Id == HtmlAttributeId.Src) {
                    MimePart image;
                    string url;

                    if (!TryGetImage (attribute.Value, out image)) {
                        htmlWriter.WriteAttribute (attribute);
                        continue;
                    }

                    url = GetDataImageSrc (image);

                    htmlWriter.WriteAttributeName (attribute.Name);
                    htmlWriter.WriteAttributeValue (url);
                } else {
                    htmlWriter.WriteAttribute (attribute);
                }
            }
        } else if (ctx.TagId == HtmlTagId.Body && !ctx.IsEndTag) {
            ctx.WriteTag (htmlWriter, false);

            // add and/or replace oncontextmenu="return false;"
            foreach (var attribute in ctx.Attributes) {
                if (attribute.Name.ToLowerInvariant () == "oncontextmenu")
                    continue;

                htmlWriter.WriteAttribute (attribute);
            }

            htmlWriter.WriteAttribute ("oncontextmenu", "return false;");
        } else {
            // pass the tag through to the output
            ctx.WriteTag (htmlWriter, true);
        }
    }

    protected override void VisitTextPart (TextPart entity)
    {
        TextConverter converter;

        if (body != null) {
            // since we've already found the body, treat this as an attachment
            attachments.Add (entity);
            return;
        }

        if (entity.IsHtml) {
            converter = new HtmlToHtml {
                HtmlTagCallback = HtmlTagCallback
            };
        } else if (entity.IsFlowed) {
            var flowed = new FlowedToHtml ();
            string delsp;

            if (entity.ContentType.Parameters.TryGetValue ("delsp", out delsp))
                flowed.DeleteSpace = delsp.ToLowerInvariant () == "yes";

            converter = flowed;
        } else {
            converter = new TextToHtml ();
        }

        body = converter.Convert (entity.Text);
    }

    protected override void VisitTnefPart (TnefPart entity)
    {
        // extract any attachments in the MS-TNEF part
        attachments.AddRange (entity.ExtractAttachments ());
    }

    protected override void VisitMessagePart (MessagePart entity)
    {
        // treat message/rfc822 parts as attachments
        attachments.Add (entity);
    }

    protected override void VisitMimePart (MimePart entity)
    {
        // realistically, if we've gotten this far, then we can treat this as an attachment
        // even if the IsAttachment property is false.
        attachments.Add (entity);
    }
}

The way to use this HtmlPreviewVisitor would be something like this:

void Render (MimeMessage message)
{
    var visitor = new HtmlPreviewVisitor ();

    message.Accept (visitor);

    plhMessage.Controls.Add (new LiteralControl (visitor.HtmlBody));
}

Note: if the HTML in the messages you plan to render all reference web URLs for their images, you can get away with just rendering the message.HtmlBody string. The HtmlPreviewVisitor solution, however, will work even if the images are embedded within the message itself.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM