跨平台的.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", "joey@friends.com"));

            //获取To头中的地址列表,添加指定的地址

            message.To.Add(new MailboxAddress("Alice", "alice@wonderland.com"));

            //获取或设置消息的主题

            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():

public static MimeMessage Load (ParserOptions options, Stream stream, bool persistent, 

                                CancellationToken cancellationToken = default (CancellationToken))

        {

            if (options == null)

                throw new ArgumentNullException (nameof (options));


            if (stream == null)

                throw new ArgumentNullException (nameof (stream));


            var parser = new MimeParser (options, stream, MimeFormat.Entity, persistent);


            return parser.ParseMessage (cancellationToken);

        }

     该方法从指定的流加载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():

public virtual void WriteTo (FormatOptions options, Stream stream, bool contentOnly, 

                            CancellationToken cancellationToken = default (CancellationToken))

        {

            if (options == null)

                throw new ArgumentNullException (nameof (options));


            if (stream == null)

                throw new ArgumentNullException (nameof (stream));


            if (!contentOnly)

                Headers.WriteTo (options, stream, cancellationToken);

        }

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

四.总结

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

原文地址:http://www.cnblogs.com/pengze0902/p/6562447.html


.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/326409.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2015蓝桥杯省赛---java---C---9(打印大X)

题目描述 思路分析 找规律 代码实现 package com.kuang.study.lanqiao;import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner sc new Scanner(System.in);int x sc.nextInt();int y sc.nextInt();char [][] arr new char[y][y…

php快速学习方法,php快速入门学习方法

一、心态在学习之前要注意调整心态&#xff0c;下面的日子是决定成败的关键&#xff0c;每天都在思考编程问题&#xff0c;不仅要懂还要会要精&#xff0c;要找成就感。成就感是学习的动力&#xff0c;心态是学习的关键&#xff0c;大家一定要坚持不能因为一点不会就放弃学习&a…

PPT基础整理

1.ppt页面组成部分&#xff1a;标题栏、功能选项卡、大纲区、功能面板、工作区 备注区、状态栏 2.插入wps自带模板&#xff1a;设计–》点击想要插入的模板 3.ppt视图&#xff1a;普通视图、大纲视图、幻灯片视图、备注页视图、母版视图 4.幻灯片制作的三板斧&#xff1a; …

MySQL trim()函数

转载自 MySQL trim()函数 MySQL TRIM函数介绍 用户输入的数据通常不是我们所预期的。有时候&#xff0c;它的格式不正确&#xff0c;例如错误的情况&#xff0c;甚至有些甚至包含前导和尾随空格以及其他不需要的字符。 为了保持数据格式正确&#xff0c;在数据库中插入或更…

老司机实战Windows Server Docker:1 初体验之各种填坑

前言 Windows Server 2016正式版发布已经有近半年时间了&#xff0c;除了看到携程的同学分享了一些Windows Server Docker的实践经验&#xff0c;网上比较深入的资料&#xff0c;不管是中文或英文的&#xff0c;都还不太多。工作中对Windows Server 2016下的Docker&#xff0c…

DOS基础整理

一、操作系统&#xff1a; 1.管理和控制计算机操作系统中的软件和硬件资源 2.合理的组织计算机工作流程 3.以方便用户使用的程序集合 二、操作系统的分类&#xff1a; 1.字符界面————DOS 2.图形界面————windows 三、启动DOS窗口&#xff1a; winR&#xff0c;打…

MySQL find_in_set()函数

转载自 MySQL find_in_set()函数 MySQL FIND_IN_SET函数简介 MySQL提供了一个名为FIND_IN_SET()的内置字符串函数&#xff0c;允许您在逗号分隔的字符串列表中查找指定字符串的位置。 下面说明了FIND_IN_SET()函数的语法。 FIND_IN_SET(needle,haystack);FIND_IN_SET()函数…

.NET Core项目从xproj+project.json向csproj迁移简介

3月7日&#xff0c;微软发布了Visual Studio 2017 RTM&#xff0c;与之一起发布的还有.NET Core Runtime 1.1.0以及.NET Core SDK 1.0.0&#xff0c;尽管这些并不是最新版&#xff0c;但也已经从preview版本升级到了正式版。所以&#xff0c;在安装Visual Studio 2017时如果启用…

马踏棋盘算法(骑士周游)+贪心优化

思路分析 代码实现 package com.atguigu.horse;import java.awt.*; import java.util.ArrayList; import java.util.Comparator;public class HorseChessboard {private static int x;//棋盘的列数private static int y;//棋盘的行数//创建一个数组&#xff0c;标记棋盘的各个…

java 路径 20,java中得到classpath和当前类的绝对路径的一些方法(路径中的%20进行替换空格)...

原网址&#xff1a;http://blog.csdn.net/shendl/article/details/1427475(注意&#xff1a;利用下面方式得到路径&#xff0c;如果路径中有空格字符&#xff0c; 那么会有"%20"进行替换&#xff0c; 所以得到之后再将"%20"替换成空格)下面是一些得到class…

网络相关配置

1.查看网络是否通畅&#xff1a;ipconfig 2.网络&#xff1a;一组相互连接的计算机 特点&#xff1a;多台计算机组成 使用物理线路进行连接 好处&#xff1a;交换数据&#xff0c;资源共享 3.网络的分类&#xff1a; 局域网&#xff1a;局限在小的地里区内和单独的建筑物…

MySQL format()函数

转载自 MySQL format()函数 MySQL FORMAT函数简介 有时&#xff0c;您使用表达式或聚合函数(如AVG)来计算数据库中的值&#xff0c;例如库存周转率&#xff0c;产品的平均价格&#xff0c;平均发票值等。 表达式的结果是十进制数&#xff0c;并带有许多小数位。要格式化这…

马踏棋盘算法(骑士周游)

思路分析 代码实现 package com.atguigu.horse;import java.awt.*; import java.util.ArrayList; import java.util.Comparator;public class HorseChessboard {private static int x;//棋盘的列数private static int y;//棋盘的行数//创建一个数组&#xff0c;标记棋盘的各个…

开源免费的.NET图像即时处理的组件ImageProcessor

承接以前的组件系列&#xff0c;这个组件系列旨在介绍.NET相关的组件&#xff0c;让大家可以在项目中有一个更好的选择&#xff0c;社区对于第三方插件的介绍还是比较少的&#xff0c;很多博文的内容主要还是介绍一些简单的操作&#xff08;很多人都说博客园现在是“hello worl…

人脸识别活体检测测试案例

最近好多人找我要关于人脸识别活体检测的案例&#xff0c;今天正好有空我就更新一下&#xff0c;先解释一下活体&#xff0c;顾名思义就是看看是否是活人在测检&#xff08;大白话解说&#xff09;&#xff0c;用技术上的话也就是看看当前操作者是否是在用照片或者其他方法来操…

php 常用的日期函数,常用php日期函数总结

php常用日期函数总结&#xff1a; 包括检查日期格式是否合法&#xff0c;检查时间是否合法时间 &#xff0c;时间比较函数&#xff0c;返回两个日期相差几秒、几分钟、几小时或几天。function check_date($date) { //检查日期是否合法日期$dateArr explode("-", $da…

MySQL nullif()函数

转载自 MySQL nullif()函数 MySQL NULLIF函数简介 NULLIF函数是接受2个参数的控制流函数之一。如果第一个参数等于第二个参数&#xff0c;则NULLIF函数返回NULL&#xff0c;否则返回第一个参数。 NULLIF函数的语法如下&#xff1a; NULLIF(expression_1,expression_2);如…

2016蓝桥杯省赛---java---B---1(有奖猜谜)

题目描述 思路分析 方案一 直接计算器(有手就行的题) 方案二 package com.kuang.study.lanqiao;import java.util.Scanner;public class Main {public static void main(String[] args) {int x777;String str"vxvxvxvxvxvxvvx";for (int i 0; i < str.length()…

Linux+Nginx+Asp.net Core部署

上篇《Docker基础入门及示例》文章介绍了Docker部署&#xff0c;以及相关.net core 的打包示例。这篇文章我将以oss.offical.site站点为例&#xff0c;主要介绍下在linux机器下完整的部署流程&#xff0c;.net core在docker容器中的运行已经介绍&#xff0c;这里.net core运行环…

php无get报错,php $_get报错怎么办

php去掉字符串最后三个字符<?phpheader (content-type:text/html;charsetutf-8); $str programming;echo "原字符串&#xff1a;{$str}";//定义一个2021-03-11 20:32:46php $_get报错的解决办法&#xff1a;当我们直接访问POST&GET页面时由于并没有传递任何…