如何使用OpenPop以HTML格式阅读电子邮件?

时间:2016-03-08 13:15:09

标签: c# asp.net pop3

我们使用OpenPop来收发电子邮件。我必须阅读消息的主题并将其显示给用户。当用户点击该消息时,我想在占位符中显示消息的内容 这是我的代码,用于显示内容,但效果不佳:

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

它在头上返回此文本:

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

并显示没有图片的消息。

如何获取电子邮件的HTML以在占位符中显示它? 另外,如何显示电子邮件中包含的图片?

1 个答案:

答案 0 :(得分:1)

在开始之前,我应该注意到你无法在Encoding.UTF8.GetBytes()上可靠地使用client.GetMessage(0).RawMessage因为(错误地)假设原始消息数据是UTF-8并且不能保证是案件。西欧的大多数电子邮件都采用拉丁文编码,俄罗斯电子邮件通常采用iso-8859-5,windows-1251或koi8-r。中文,日文和韩文电子邮件几乎总是在其中一个区域字符集中(通常分别为gbk / big5,iso-2022-jp和euc-kr)。

现在已经解决了......让我们继续讨论你的主要问题。

使用MailKit比使用OpenPOP要坦率地说你要做的事情要坦率得多,所以我将告诉你如何使用MailKit来实现它:

要获取消息,MailKit与OpenPOP非常相似:

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);
            }
        }
    }
}

要使用MailKit呈现消息,最简单的方法是编写自己的MimeVisitor,如下所示:

/// <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);
    }
}

使用此HtmlPreviewVisitor的方法是这样的:

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

    message.Accept (visitor);

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

注意:如果您计划呈现所有引用的邮件中的HTML   他们的图片的网址,你可以逃脱只是渲染   message.HtmlBody字符串。但是,HtmlPreviewVisitor解决方案   即使图像嵌入在信息本身中也会有效。