跨平台的.NET邮件协议MailKit组件解析

发起的.NET Core开源组织号召,进展的速度是我自己也没有想到的,很多园友都积极参与(虽然有些人诚心砸场子,要是以我以前的宝脾气,这会应该被我打住院了吧,不过幸好是少数,做一件事总有人说好,也有人说是用武汉话说“闹眼子”),.NET社区不是没有乐于共享知识的人,只是没有一个完整和良好的生态环境,总之希望国内的.NET发展越来越强大。我在这里想到一句话“我们希望自己可以做巨浪,但我们也甘愿做巨浪来袭前的小浪”。

上面扯淡完毕(我这人干正事前,都要将一些扯淡的话,这个习惯改不掉了...)

项目中为了及时的通信,有直接发数据到页面,也有利用短信通知,也有我门今天介绍的邮件组件。我们今天的主要任务就是讲解一下有一个.NET的免费开源的邮件组件MailKit。本文将一如既往的结合实例和组件底层代码讲解一下相关组件的知识。(项目招人的时候,我都会问一下.NET的底层原理,有一个大神问我这样有什么意义吗?我们也写不出.NET底层那样的优秀处理方式,为何取了解这些,其实我个人觉得,问底层的原理,只是向为了跟好的处理一些程序出现的问题,以及对程序编码的时候,选择最合适的方式提升性能,任何一种方式都有优势和劣势,.NET的类库代码也是如此,如果我们知道.NET的底层实现,我们在项目的需求实现时,可以根据.NET底层实现,选择合适的方式,以求性能最优)。

一.Mailkit组件概述

项目中使用Email的操作机会比较多,一般稍微大一点的项目,都会使用到邮件操作这一个操作。对于.NET邮件操作的组件和方式比较多,今天我们就介绍一款邮件操作的组件MailKit,这个邮件组件是一个开源免费的,我们现在就来了解一下这一个组件的特点。MimeKit旨在通过尽可能接近地遵循MIME规范来解决这个问题,同时还为程序员提供了一个非常容易使用的高级API。

组件的支持的客户端类型比较多,例如SMTP客户端、POP3客户端、IMAP客户端。该组件是一个跨平台的Email组件,该组件支持.NET 4.0,.NET 4.5,Xamarin.Android,Xamarin.iOS,Windows Phone 8.1等等平台。该组件提供了一个MIME解析器,组件具备的解析特性灵活、性能高、很好的处理各种各样的破碎的MIME格式化。MimeKit的性能实际上与GMime相当。

该组件在安全性的还是比较高的,处理安全的方式较多,SASL认证、支持S / MIME v3.2、支持OpenPGP、支持DKIM签名等等方式。Mailkit组件可以通过CancellationToken取消对应的操作,CancellationToken传播应取消操作的通知,一个的CancellationToken使线程,线程池工作项目之间,或取消合作任务的对象。过实例化CancellationTokenSource对象来创建取消令牌,该对象管理从其CancellationTokenSource.Token属性检索的取消令牌。然后,将取消令牌传递到应该收到取消通知的任意数量的线程,任务或操作。令牌不能用于启动取消。

MailKit组件支持异步操作,在内部编写的有关I/O异步操作的类。

二.MailKit实例:

上面介绍了MailKit组件的背景和特点,这里就介绍一下Email组件的简单应用。

1.创建邮件方式:

 public void SentEmail(string path)
        {            var message = new MimeMessage();            //获取From标头中的地址列表,添加指定的地址
            message.From.Add(new MailboxAddress("Joey", "[email protected]"));            //获取To头中的地址列表,添加指定的地址
            message.To.Add(new MailboxAddress("Alice", "[email protected]"));            //获取或设置消息的主题
            message.Subject = "How you doin?";            // 创建我们的消息文本,就像以前一样(除了不设置为message.Body)
            var body = new TextPart("plain")
            {
                Text = @"Hey Alice-- Joey"
            };            // 为位于路径的文件创建图像附件
            var attachment = new MimePart("image", "gif")
            {
                ContentObject = new ContentObject(File.OpenRead(path), ContentEncoding.Default),
                ContentDisposition = new ContentDisposition(ContentDisposition.Attachment),
                ContentTransferEncoding = ContentEncoding.Base64,
                FileName = Path.GetFileName(path)
            };            // 现在创建multipart / mixed容器来保存消息文本和图像附件
            var multipart = new Multipart("mixed")
            {
                body, attachment
            };            // 现在将multipart / mixed设置为消息正文 
            message.Body = multipart;
        }

调用该组件发送邮件和为邮件添加附件是比较简单的,第一步是实例化MimeMessage对象,对于该对象的解析将在下面进行,得到MimeMessage对象后,指定邮件的地址和主题等等相关信息。第二步实例化TextPart对象,为对象设定文本信息。若需要问邮件创建文件的附件,可以使用MimePart对象,包含内容(如消息正文文本或)的叶节点MIME部分一个附件。第四步为创建的邮件主体和文本以及附件信息后,可以创建Multipart对象,创建邮件容器,用来装载文本信息和附件。最后调用MimeMessage.body属性获取或设置消息的正文。

2.邮件信息的解析:

var message = MimeMessage.Load(stream);

邮件的信息我们需要进行对应的解析,这里我们使用MimeMessage的Load方法,该方法从指定的流加载MimeKit.MimeMessage。另一个加载数据的方式,可以使用MimeParser类,这里就不再解析了。

3.邮件的接收:

   public static void HandleMimeEntity(MimeEntity entity)
        {            //MimeEntity转化为Multipart实体
            var multipart = entity as Multipart;            if (multipart != null)
            {                for (int i = 0; i < multipart.Count; i++)
                    HandleMimeEntity(multipart[i]);                return;
            }            var rfc822 = entity as MessagePart;            if (rfc822 != null)
            {                var message = rfc822.Message;
                HandleMimeEntity(message.Body);                return;
            }            var part = (MimePart)entity;
        }

以上是对接收到的消息的一个遍历,采用递归遍历MIME结构。MIME是内容的树结构,很像一个文件系统。MIME确实定义了一组通用规则,用于邮件客户端如何解释MIME部分的树结构。的 内容处置头是为了给接收客户端提供提示以哪些部分是为了显示作为消息体的一部分,并且意在被解释为附件。另外两种方式这离就不做介绍了。

三.MailKit核心对象解析

上面介绍了Email的基本操作就不做过多的介绍,在使用该组件时,较为的简单。这里就来看看该组件的类型结构和一些核心对象。类库结构有如下图:

1.MimeMessage.Load():

  MimeMessage Load (ParserOptions options, Stream stream,  persistent, 
                                CancellationToken cancellationToken =  (options ==   (stream ==   parser =

该方法从指定的流加载MimeMessage,具有6个方法重载。该方法返回一个MimeMessage对象,有源码可以看出,在该方法内部创建了一个MimeParser对象,MimeParser包含内容(例如邮件正文文本或附件)的叶节点MIME部分。调用ParseMessage方法,解析来自流的消息。

2.TextPart.Text:

public string Text {            get {                if (ContentObject == null)                    return string.Empty;                var charset = ContentType.Parameters["charset"];                using (var memory = new MemoryStream ()) {
                    ContentObject.DecodeTo (memory);                    var content = memory.ToArray ();
                    Encoding encoding = null;                    if (charset != null) {                        try {
                            encoding = CharsetUtils.GetEncoding (charset);
                        } catch (NotSupportedException) {
                        }
                    }                    if (encoding == null) {                        try {                            return CharsetUtils.UTF8.GetString (content, 0, (int) memory.Length);
                        } catch (DecoderFallbackException) {
                            encoding = CharsetUtils.Latin1;
                        }
                    }                    return encoding.GetString (content, 0, (int) memory.Length);
                }
            }            set {
                SetText (Encoding.UTF8, value);
            }
        }

该属性获取解码的文本内容。该属性是一个可读可写的属性。ContentType.Parameters["charset"]用于获取charset参数的值。该方法用来将参数的值设置为数据流并设置对应的编码。看到这里的异常处理结构,就想简单的谈几句,.NET的异常比较的薄弱,很多时候在写.NET的异常时就更加的简单,以上是对异常知识捕获,有些地方并没有做处理,有些地方是对异常的地方进行恢复。

3.MimeEntity.WriteTo():

   WriteTo (FormatOptions options, Stream stream,  contentOnly, 
                            CancellationToken cancellationToken =  (options ==   (stream ==   (!

该方法将MimeEntity写入到指定的数据流中,该方法接受参数options格式选项。stream输出数据流,contentOnly判断是否可写。该方法定义为虚方法,在继承此方法后,可以在子类种对该方法进行重写。

四.总结

本人觉得在项目开发中,如果引入了第三方组件,我们尽量引入组件的源码,这样我们对整个组件的结构有一个认识,组件的实现方式我们也可以进行细致了解,尤其是我们在进行调试的事后更加有用,我们可以逐一的进行断点调试。以上是对该组件的一个简单介绍,有兴趣的可以去深入的了解和学习。

时间: 2024-08-02 16:30:20

跨平台的.NET邮件协议MailKit组件解析的相关文章

UDP协议疑难杂症全景解析

转载:http://blog.csdn.net/dog250/article/details/6896949 UDP协议疑难杂症全景解析 2011-10-22 19:26 2989人阅读 评论(4) 收藏 举报 tcp网络算法交通socket通讯 如今,但凡说精通网络的,第二个意思就是"精通TCP",事实上,很多自称精通TCP的家伙们只是精通socket接口而已,对TCP行为精通的并不多,笔者也不算精通,但绝对是中等以上水平.如果你真的精通TCP行为,那么本文不读也罢,直接发邮件给我,

OpenStack入门 之 各组件解析

学习目标: 掌握 OpenStack 的各组件的架构和功能 本次笔记的内容有: Nova 组件解析 Swift 组件解析 Cinder 组件解析 Neutron 组件解析 Horizon 组件解析 Glance 组件解析 Keystone 组件解析 是常用的 7 个组件: 负责虚拟机创建.管理和销毁.提供计算资源服务的 Nova: 提供对象存储服务的分布式存储 Swift: 提供块存储服务的 Cinder: 提供虚拟机镜像管理和存储服务的 Glance: 软件定义网络项目 Neutron: 提供

三、OpenStack入门 之 各组件解析

OpenStack入门 之 各组件解析 写在前面 学习目标: 掌握 OpenStack 的各组件的架构和功能 本次笔记的内容有: Nova 组件解析 Swift 组件解析 Cinder 组件解析 Neutron 组件解析 Horizon 组件解析 Glance 组件解析 Keystone 组件解析 是常用的 7 个组件: 负责虚拟机创建.管理和销毁.提供计算资源服务的 Nova: 提供对象存储服务的分布式存储 Swift: 提供块存储服务的 Cinder: 提供虚拟机镜像管理和存储服务的 Gla

Python——POP3邮件协议

一.POP3协议用于收取邮件 二.POP3协议常用方法 user(login):想服务器发送登录名,并显示服务器的响应,表示服务器正在等待该用户的输入密码 pass_(passwd):在用户使用user登陆后,发送passwd,如果登录失败,则抛出异常 stat():返回邮件的状态 list([msgnum]):stat()的扩展,如果给定msgnum,则返回指定消息数据 retr(msgnum):从服务器中得到消息msgnum,并设置"已读"标志 dele(msgnum):把消息ms

【转载】TCP协议疑难杂症全景解析

说明: 1).本文以TCP的发展历程解析容易引起混淆,误会的方方面面2).本文不会贴大量的源码,大多数是以文字形式描述,我相信文字看起来是要比代码更轻松的3).针对对象:对TCP已经有了全面了解的人.因为本文不会解析TCP头里面的每一个字段或者3次握手的细节,也不会解释慢启动和快速重传的定义4).除了<TCP/IP详解>(卷一,卷二)以及<Unix网络编程>以及Linux源代码之外,学习网络更好的资源是RFC 5).本文给出一个提纲,如果想了解细节,请直接查阅RFC 6).翻来覆去

【SMTP简单邮件协议的服务配置】

**********************************************SMTP(简单邮件协议)***************************************************SMTP简单邮件协议,从属TCP/IP簇的 TCP中.端口号为25.[前置:配置 两个DNS主机,一个主maillinux,一个副hxl:maillinux(主DNS服务器,设置/etc/name.conf;/etc/name.rfc1912.zone/;~.zone的两个文件)]

日志组件解析

日志组件解析 NetCore中的日志(1)日志组件解析 0x00 问题的产生 日志记录功能在开发中很常用,可以记录程序运行的细节,也可以记录用户的行为.在之前开发时我一般都是用自己写的小工具来记录日志,输出目标包含控制台.文本文件.数据库,一般都是创建全局的Logger,在需要记录日志的地方调用相应的Logger输出至相应目标.遇到输出目标多了有时候也感觉挺麻烦的,不过也还能接受.开始学习.NetCore后接触到了日志记录框架(Logging组件),虽然完全可以用之前的方式记录日志,不过应该使用

邮件协议(SMTP)性能测试总结(Foxmail邮箱)

先介绍一下邮件协议SMTP的工作机制(连接和发送过程),用wireshark工具抓包进行分析,如下: SMTP协议的工作机制(连接和发送过程): 1.建立TCP连接,并将邮件服务器地址给客户端: 2.客户端发送EHLO命令以标识发件人自己的身份,然后客户端登录邮件服务器: 3.客户端先标示电子邮件的发件人发送MAIL命令,服务器端以OK作为响应,表明准备接收: 4.客户端发送RCPT 命令,以标识该电子邮件的计划接收人,可以有多个RCPT行, 服务器端以OK作为响应,表示愿意为收件人接收邮件:

.NetCore中的日志(1)日志组件解析

.NetCore中的日志(1)日志组件解析 0x00 问题的产生 日志记录功能在开发中很常用,可以记录程序运行的细节,也可以记录用户的行为.在之前开发时我一般都是用自己写的小工具来记录日志,输出目标包含控制台.文本文件.数据库,一般都是创建全局的Logger,在需要记录日志的地方调用相应的Logger输出至相应目标.遇到输出目标多了有时候也感觉挺麻烦的,不过也还能接受.开始学习.NetCore后接触到了日志记录框架(Logging组件),虽然完全可以用之前的方式记录日志,不过应该使用更通用的方式