zoukankan      html  css  js  c++  java
  • 创建基于MailKit和MimeKit的.NET基础邮件服务

       邮件服务是一般的系统都会拥有和需要的功能,但是对于.NET项目来说,邮件服务的创建和使用会较为的麻烦。.NET对于邮件功能提供了System.Net.Mail用于创建邮件服务,该基础服务提供邮件的基础操作,并且使用也较为的简单。对于真正将该功能使用于项目的人,就会慢慢发现其中的优缺点,甚至有些时候不能忍受其中的问题。在这里介绍一种微软用于替代System.Net.Mail的邮件服务组件MailKit和MimeKit,官网地址:http://www.mimekit.net/。GitHub地址:https://github.com/jstedfast/MimeKit。下面就具体的介绍一下。

      一.MailKit和MimeKit基础概述:

           MailKit组件的支持的客户端类型比较多,例如SMTP客户端、POP3客户端、IMAP4客户端。该组件是一个跨平台的Email组件,该组件支持.NET 4.0,.NET 4.5,Xamarin.Android,Xamarin.iOS,Windows Phone 8.1等等平台。

         640?wx_fmt=png&wxfrom=5&wx_lazy=1

          MimeKit提供了一个MIME解析器,组件具备的解析特性灵活、性能高、很好的处理各种各样的破碎的MIME格式化。MimeKit的性能实际上与GMime相当。

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

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

      二.创建基础邮件服务:

               介绍过MailKit和MimeKit组建的基础信息,接下来就介绍一下如何使用两个组件的基本功能,在这里我将基本操作做了一个简单的封装,一般的项目可以直接引用封装好的类,大家可以根据实际的情况对该组件进行扩展。

              1.邮件发送基础服务API

    /// <summary>

        /// 邮件服务API

        /// </summary>

        public static class MailServiceApi

        {

            /// <summary>

            /// 发送邮件

            /// </summary>

            /// <param name="mailBodyEntity">邮件基础信息</param>

            /// <param name="sendServerConfiguration">发件人基础信息</param>

            public static SendResultEntity SendMail(MailBodyEntity mailBodyEntity,

                SendServerConfigurationEntity sendServerConfiguration)

            {

                if (sendServerConfiguration == null)

                {

                    throw new ArgumentNullException();

                }

                if (sendServerConfiguration == null)

                {

                    throw new ArgumentNullException();

                }

                var sendResultEntity = new SendResultEntity();

                using (var client = new SmtpClient(new ProtocolLogger(CreateMailLog())))

                {

                    client.ServerCertificateValidationCallback = (s, c, h, e) => true;

                    Connection(mailBodyEntity, sendServerConfiguration, client, sendResultEntity);

                    if (sendResultEntity.ResultStatus == false)

                    {

                        return sendResultEntity;

                    }

                    SmtpClientBaseMessage(client);

                    Authenticate(mailBodyEntity, sendServerConfiguration, client, sendResultEntity);

                    if (sendResultEntity.ResultStatus == false)

                    {

                        return sendResultEntity;

                    }

                    Send(mailBodyEntity, sendServerConfiguration, client, sendResultEntity);

                    if (sendResultEntity.ResultStatus == false)

                    {

                        return sendResultEntity;

                    }

                    client.Disconnect(true);

                }

                return sendResultEntity;

            }

            /// <summary>

            /// 连接服务器

            /// </summary>

            /// <param name="mailBodyEntity">邮件内容</param>

            /// <param name="sendServerConfiguration">发送配置</param>

            /// <param name="client">客户端对象</param>

            /// <param name="sendResultEntity">发送结果</param>

            public static void Connection(MailBodyEntity mailBodyEntity, SendServerConfigurationEntity sendServerConfiguration,

                SmtpClient client, SendResultEntity sendResultEntity)

            {

                try

                {

                    client.Connect(sendServerConfiguration.SmtpHost, sendServerConfiguration.SmtpPort);

                }

                catch (SmtpCommandException ex)

                {

                    sendResultEntity.ResultInformation = $"尝试连接时出错:{0}" + ex.Message;

                    sendResultEntity.ResultStatus = false;

                }

                catch (SmtpProtocolException ex)

                {

                    sendResultEntity.ResultInformation = $"尝试连接时的协议错误:{0}" + ex.Message;

                    sendResultEntity.ResultStatus = false;

                }

                catch (Exception ex)

                {

                    sendResultEntity.ResultInformation = $"服务器连接错误:{0}" + ex.Message;

                    sendResultEntity.ResultStatus = false;

                }

            }

            /// <summary>

            /// 账户认证

            /// </summary>

            /// <param name="mailBodyEntity">邮件内容</param>

            /// <param name="sendServerConfiguration">发送配置</param>

            /// <param name="client">客户端对象</param>

            /// <param name="sendResultEntity">发送结果</param>

            public static void Authenticate(MailBodyEntity mailBodyEntity, SendServerConfigurationEntity sendServerConfiguration,

                SmtpClient client, SendResultEntity sendResultEntity)

            {

                try

                {

                    client.Authenticate(sendServerConfiguration.SenderAccount, sendServerConfiguration.SenderPassword);

                }

                catch (AuthenticationException ex)

                {

                    sendResultEntity.ResultInformation = $"无效的用户名或密码:{0}" + ex.Message;

                    sendResultEntity.ResultStatus = false;

                }

                catch (SmtpCommandException ex)

                {

                    sendResultEntity.ResultInformation = $"尝试验证错误:{0}" + ex.Message;

                    sendResultEntity.ResultStatus = false;

                }

                catch (SmtpProtocolException ex)

                {

                    sendResultEntity.ResultInformation = $"尝试验证时的协议错误:{0}" + ex.Message;

                    sendResultEntity.ResultStatus = false;

                }

                catch (Exception ex)

                {

                    sendResultEntity.ResultInformation = $"账户认证错误:{0}" + ex.Message;

                    sendResultEntity.ResultStatus = false;

                }

            }

            /// <summary>

            /// 发送邮件

            /// </summary>

            /// <param name="mailBodyEntity">邮件内容</param>

            /// <param name="sendServerConfiguration">发送配置</param>

            /// <param name="client">客户端对象</param>

            /// <param name="sendResultEntity">发送结果</param>

            public static void Send(MailBodyEntity mailBodyEntity, SendServerConfigurationEntity sendServerConfiguration,

                SmtpClient client, SendResultEntity sendResultEntity)

            {

                try

                {

                    client.Send(MailMessage.AssemblyMailMessage(mailBodyEntity));

                }

                catch (SmtpCommandException ex)

                {

                    switch (ex.ErrorCode)

                    {

                        case SmtpErrorCode.RecipientNotAccepted:

                            sendResultEntity.ResultInformation = $"收件人未被接受:{ex.Message}";

                            break;

                        case SmtpErrorCode.SenderNotAccepted:

                            sendResultEntity.ResultInformation = $"发件人未被接受:{ex.Message}";

                            break;

                        case SmtpErrorCode.MessageNotAccepted:

                            sendResultEntity.ResultInformation = $"消息未被接受:{ex.Message}";

                            break;

                    }

                    sendResultEntity.ResultStatus = false;

                }

                catch (SmtpProtocolException ex)

                {

                    sendResultEntity.ResultInformation = $"发送消息时的协议错误:{ex.Message}";

                    sendResultEntity.ResultStatus = false;

                }

                catch (Exception ex)

                {

                    sendResultEntity.ResultInformation = $"邮件接收失败:{ex.Message}";

                    sendResultEntity.ResultStatus = false;

                }

            }

            /// <summary>

            /// 获取SMTP基础信息

            /// </summary>

            /// <param name="client">客户端对象</param>

            /// <returns></returns>

            public static MailServerInformation SmtpClientBaseMessage(SmtpClient client)

            {

                var mailServerInformation = new MailServerInformation

                {

                    Authentication = client.Capabilities.HasFlag(SmtpCapabilities.Authentication),

                    BinaryMime = client.Capabilities.HasFlag(SmtpCapabilities.BinaryMime),

                    Dsn = client.Capabilities.HasFlag(SmtpCapabilities.Dsn),

                    EightBitMime = client.Capabilities.HasFlag(SmtpCapabilities.EightBitMime),

                    Size = client.MaxSize

                };

                return mailServerInformation;

            }

            /// <summary>

            /// 创建邮件日志文件

            /// </summary>

            /// <returns></returns>

            public static string CreateMailLog()

            {

                var logPath = AppDomain.CurrentDomain.BaseDirectory + "/DocumentLog/" +

                    Guid.NewGuid() + ".txt";

                if (File.Exists(logPath)) return logPath;

                var fs = File.Create(logPath);

                fs.Close();

                return logPath;

            }

        }

       2.组装邮件消息:

    /// <summary>

        /// 邮件信息

        /// </summary>

        public static class MailMessage

        {

            /// <summary>

            /// 组装邮件文本/附件邮件信息

            /// </summary>

            /// <param name="mailBodyEntity">邮件消息实体</param>

            /// <returns></returns>

            public static MimeMessage AssemblyMailMessage(MailBodyEntity mailBodyEntity)

            {

                if (mailBodyEntity == null)

                {

                    throw new ArgumentNullException(nameof(mailBodyEntity));

                }

                var message = new MimeMessage();

                //设置邮件基本信息

                SetMailBaseMessage(message, mailBodyEntity);

                var multipart = new Multipart("mixed");

                //插入文本消息

                if (string.IsNullOrEmpty(mailBodyEntity.MailTextBody) == false)

                {

                    var alternative = new MultipartAlternative

                    {

                        AssemblyMailTextMessage(mailBodyEntity.MailTextBody, mailBodyEntity.MailBodyType)

                     };

                    multipart.Add(alternative);

                }

                //插入附件

                if (mailBodyEntity.MailFilePath != null && File.Exists(mailBodyEntity.MailFilePath) == false)

                {

                    var mimePart = AssemblyMailAttachmentMessage(mailBodyEntity.MailFileType, mailBodyEntity.MailFileSubType,

                         mailBodyEntity.MailFilePath);

                    multipart.Add(mimePart);

                }

                //组合邮件内容

                message.Body = multipart;

                return message;

            }

            /// <summary>

            /// 设置邮件基础信息

            /// </summary>

            /// <param name="minMessag"></param>

            /// <param name="mailBodyEntity"></param>

            /// <returns></returns>

            public static MimeMessage SetMailBaseMessage(MimeMessage minMessag, MailBodyEntity mailBodyEntity)

            {

                if (minMessag == null)

                {

                    throw new ArgumentNullException();

                }

                if (mailBodyEntity == null)

                {

                    throw new ArgumentNullException();

                }

                //插入发件人

                minMessag.From.Add(new MailboxAddress(mailBodyEntity.Sender, mailBodyEntity.SenderAddress));

                //插入收件人

                foreach (var recipients in mailBodyEntity.Recipients)

                {

                    minMessag.To.Add(new MailboxAddress(recipients));

                }

                //插入抄送人

                foreach (var cC in mailBodyEntity.Cc)

                {

                    minMessag.Cc.Add(new MailboxAddress(cC));

                }

                //插入主题

                minMessag.Subject = mailBodyEntity.Subject;

                return minMessag;

            }

            /// <summary>

            /// 组装邮件文本信息

            /// </summary>

            /// <param name="mailBody">邮件文本内容</param>

            /// <param name="textPartType">邮件文本类型(plain,html,rtf,xml)</param>

            /// <returns></returns>

            public static TextPart AssemblyMailTextMessage(string mailBody, string textPartType)

            {

                if (string.IsNullOrEmpty(mailBody))

                {

                    throw new ArgumentNullException();

                }

                if (string.IsNullOrEmpty(textPartType))

                {

                    throw new ArgumentNullException();

                }

                var textBody = new TextPart(textPartType)

                {

                    Text = mailBody

                };

                return textBody;

            }

            /// <summary>

            /// 组装邮件附件信息

            /// </summary>

            /// <param name="fileAttachmentType">附件类型(image,application)</param>

            /// <param name="fileAttachmentSubType">附件子类型 </param>

            /// <param name="fileAttachmentPath">附件路径</param>

            /// <returns></returns>

            public static MimePart AssemblyMailAttachmentMessage(string fileAttachmentType, string fileAttachmentSubType, string fileAttachmentPath)

            {

                if (string.IsNullOrEmpty(fileAttachmentSubType))

                {

                    throw new ArgumentNullException();

                }

                if (string.IsNullOrEmpty(fileAttachmentType))

                {

                    throw new ArgumentNullException();

                }

                if (string.IsNullOrEmpty(fileAttachmentPath))

                {

                    throw new ArgumentNullException();

                }

                var attachment = new MimePart(fileAttachmentType, fileAttachmentSubType)

                {

                    Content = new MimeContent(File.OpenRead(fileAttachmentPath)),

                    ContentDisposition = new ContentDisposition(ContentDisposition.Attachment),

                    ContentTransferEncoding = ContentEncoding.Base64,

                    FileName = Path.GetFileName(fileAttachmentPath)

                };

                return attachment;

            }

        }

       3.邮件基础服务实体:

    /// <summary>

        /// 邮件内容实体

        /// </summary>

        public class MailBodyEntity

        {

            /// <summary>

            /// 邮件文本内容

            /// </summary>

            public string MailTextBody { get; set; }

            /// <summary>

            /// 邮件内容类型

            /// </summary>

            public string MailBodyType { get; set; }

            /// <summary>

            /// 邮件附件文件类型

            /// </summary>

            public string MailFileType { get; set; }

            /// <summary>

            /// 邮件附件文件子类型

            /// </summary>

            public string MailFileSubType { get; set; }

            /// <summary>

            /// 邮件附件文件路径

            /// </summary>

            public string MailFilePath { get; set; }

            /// <summary>

            /// 收件人

            /// </summary>

            public List<string> Recipients { get; set; }

            /// <summary>

            /// 抄送

            /// </summary>

            public List<string> Cc { get; set; }

            /// <summary>

            /// 发件人

            /// </summary>

            public string Sender { get; set; }

            /// <summary>

            /// 发件人地址

            /// </summary>

            public string SenderAddress { get; set; }

            /// <summary>

            /// 邮件主题

            /// </summary>

            public string Subject { get; set; }

            /// <summary>

            /// 邮件内容

            /// </summary>

            public string Body { get; set; }

        }

        /// <summary>

        /// 邮件服务器基础信息

        /// </summary>

        public class MailServerInformation

        {

            /// <summary>

            /// SMTP服务器支持SASL机制类型

            /// </summary>

            public bool Authentication { get; set; }

            /// <summary>

            /// SMTP服务器对消息的大小

            /// </summary>

            public uint Size { get; set; }

            /// <summary>

            /// SMTP服务器支持传递状态通知

            /// </summary>

            public bool Dsn { get; set; }

            /// <summary>

            /// SMTP服务器支持Content-Transfer-Encoding

            /// </summary>

            public bool EightBitMime { get; set; }

            /// <summary>

            /// SMTP服务器支持Content-Transfer-Encoding

            /// </summary>

            public bool BinaryMime { get; set; }

            /// <summary>

            /// SMTP服务器在消息头中支持UTF-8

            /// </summary>

            public string UTF8 { get; set; }

        }

        /// <summary>

        /// 邮件发送结果

        /// </summary>

        public class SendResultEntity

        {

            /// <summary>

            /// 结果信息

            /// </summary>

            public string ResultInformation { get; set; } = "发送成功!";

            /// <summary>

            /// 结果状态

            /// </summary>

            public bool ResultStatus { get; set; } = true;

        }

        /// <summary>

        /// 邮件发送服务器配置

        /// </summary>

        public class SendServerConfigurationEntity

        {

            /// <summary>

            /// 邮箱SMTP服务器地址

            /// </summary>

            public string SmtpHost { get; set; }

            /// <summary>

            /// 邮箱SMTP服务器端口

            /// </summary>

            public int SmtpPort { get; set; }

            /// <summary>

            /// 是否启用IsSsl

            /// </summary>

            public bool IsSsl { get; set; }

            /// <summary>

            /// 邮件编码

            /// </summary>

            public string MailEncoding { get; set; }

            /// <summary>

            /// 发件人账号

            /// </summary>

            public string SenderAccount { get; set; }

            /// <summary>

            /// 发件人密码

            /// </summary>

            public string SenderPassword { get; set; }

        }

    上面提供了借助MailKit组建创建发送邮件服务,分别是创建邮件服务器连接,组装邮件基础信息,邮件基础实体。发送邮件的基础服务比较的多,下面介绍一下邮件的接收。

    /// <summary>

        /// 跟投邮件服务API

        /// </summary>

        public static class ReceiveEmailServiceApi

        {

            /// <summary>

            /// 设置发件人信息

            /// </summary>

            /// <returns></returns>

            public static SendServerConfigurationEntity SetSendMessage()

            {

                var sendServerConfiguration = new SendServerConfigurationEntity

                {

                    SmtpHost = ConfigurationManager.AppSettings["SmtpServer"],

                    SmtpPort = int.Parse(ConfigurationManager.AppSettings["SmtpPort"]),

                    IsSsl = Convert.ToBoolean(ConfigurationManager.AppSettings["IsSsl"]),

                    MailEncoding = ConfigurationManager.AppSettings["MailEncoding"],

                    SenderAccount = ConfigurationManager.AppSettings["SenderAccount"],

                    SenderPassword = ConfigurationManager.AppSettings["SenderPassword"]

                };

                return sendServerConfiguration;

            }

            /// <summary>

            /// 接收邮件

            /// </summary>

            public static void ReceiveEmail()

            {

                var sendServerConfiguration = SetSendMessage();

                if (sendServerConfiguration == null)

                {

                    throw new ArgumentNullException();

                }

                using (var client = new ImapClient(new ProtocolLogger(CreateMailLog())))

                {

                    client.Connect(sendServerConfiguration.SmtpHost, sendServerConfiguration.SmtpPort,

                        SecureSocketOptions.SslOnConnect);

                    client.Authenticate(sendServerConfiguration.SenderAccount, sendServerConfiguration.SenderPassword);

                    client.Inbox.Open(FolderAccess.ReadOnly);

                    var uids = client.Inbox.Search(SearchQuery.All);

                    foreach (var uid in uids)

                    {

                        var message = client.Inbox.GetMessage(uid);

                        message.WriteTo($"{uid}.eml");

                    }

                    client.Disconnect(true);

                }

            }

            /// <summary>

            /// 下载邮件内容

            /// </summary>

            public static void DownloadBodyParts()

            {

                var sendServerConfiguration = SetSendMessage();

                using (var client = new ImapClient())

                {

                    client.Connect(sendServerConfiguration.SmtpHost, sendServerConfiguration.SmtpPort,

                        SecureSocketOptions.SslOnConnect);

                    client.Authenticate(sendServerConfiguration.SenderAccount, sendServerConfiguration.SenderPassword);

                    client.Inbox.Open(FolderAccess.ReadOnly);

                    // 搜索Subject标题包含“MimeKit”或“MailKit”的邮件

                    var query = SearchQuery.SubjectContains("MimeKit").Or(SearchQuery.SubjectContains("MailKit"));

                    var uids = client.Inbox.Search(query);

                    // 获取搜索结果的摘要信息(我们需要UID和BODYSTRUCTURE每条消息,以便我们可以提取文本正文和附件)

                    var items = client.Inbox.Fetch(uids, MessageSummaryItems.UniqueId | MessageSummaryItems.BodyStructure);

                    foreach (var item in items)

                    {

                        // 确定一个目录来保存内容

                        var directory = Path.Combine(AppDomain.CurrentDomain.BaseDirectory + "/MailBody", item.UniqueId.ToString());

                        Directory.CreateDirectory(directory);

                        // IMessageSummary.TextBody是一个便利的属性,可以为我们找到“文本/纯文本”的正文部分

                        var bodyPart = item.TextBody;

                        // 下载'text / plain'正文部分

                        var body = (TextPart) client.Inbox.GetBodyPart(item.UniqueId, bodyPart);

                        // TextPart.Text是一个便利的属性,它解码内容并将结果转换为我们的字符串

                        var text = body.Text;

                        File.WriteAllText(Path.Combine(directory, "body.txt"), text);

                        // 现在遍历所有附件并将其保存到磁盘

                        foreach (var attachment in item.Attachments)

                        {

                            // 像我们对内容所做的那样下载附件

                            var entity = client.Inbox.GetBodyPart(item.UniqueId, attachment);

                            // 附件可以是message / rfc822部件或常规MIME部件

                            var messagePart = entity as MessagePart;

                            if (messagePart != null)

                            {

                                var rfc822 = messagePart;

                                var path = Path.Combine(directory, attachment.PartSpecifier + ".eml");

                                rfc822.Message.WriteTo(path);

                            }

                            else

                            {

                                var part = (MimePart) entity;

                                // 注意:这可能是空的,但大多数会指定一个文件名

                                var fileName = part.FileName;

                                var path = Path.Combine(directory, fileName);

                                // decode and save the content to a file

                                using (var stream = File.Create(path))

                                    part.Content.DecodeTo(stream);

                            }

                        }

                    }

                    client.Disconnect(true);

                }

            }

            /// <summary>

            /// 创建邮件日志文件

            /// </summary>

            /// <returns></returns>

            public static string CreateMailLog()

            {

                var logPath = AppDomain.CurrentDomain.BaseDirectory + "/DocumentLog/" +

                    DateTime.Now.ToUniversalTime().ToString(CultureInfo.InvariantCulture) + ".txt";

                if (File.Exists(logPath)) return logPath;

                var fs = File.Create(logPath);

                fs.Close();

                return logPath;

            }

        }

    面只是简单的介绍了邮件的接收,如果需要更加深入的了解功能,可以进一步对组件源码进行解析,该组件的文档为较为的丰富。

      三.组件使用感悟:

                MailKit和MimeKit组件在项目的使用中较为的便捷,基本包含了所有的基础邮件服务操作。组件提供的SmtpClient类提供的功能很丰富,例如连接邮件服务器,邮件账户认证,组装邮件消息,获取邮件服务器配置信息等等方法的提供,可以让我们在项目中快速的获取邮件服务的所有信息。

               使用过邮件功能的项目 都会有困扰,客户端与邮件服务器的连接是否成功,以及邮件是否发送成功状态没有办法很快的获取,只能根据邮件服务器返回的一场状态进行判断。但是MailKit提供对应的方法和异常类,对邮件服务器返回的异常信息进行解析,客户端可以根据这些异常类获取邮件状态。

               MailKit组件的提供了ProtocolLogger类,该类用于记录SMTP操作基础信息,该类作用为记录邮件服务日志。在邮件发送完毕后,需要及时的关闭连接,调用Disconnect(true)方法。

    原文:https://www.cnblogs.com/pengze0902/p/8519715.html

  • 相关阅读:
    golang类型判断
    golang文件相对路径问题
    golang中数组与切片的区别
    golang的一些基础数据类型转换
    golang变量的注意
    Oracle数据库导入导出总结(dmp文件)
    Ajax,谷歌提示AutoCompleteExtender控件
    验证控件插图扩展控件ValidatorCalloutExtender(用于扩展验证控件)和TextBoxWatermarkExtender
    当使用母版页时JavaScript客户端获取服务器控件的Id
    实现GridView翻页并且实现CheckBox选中功能的保持
  • 原文地址:https://www.cnblogs.com/lhxsoft/p/10801178.html
Copyright © 2011-2022 走看看