MailKit是Net下免费开源的邮箱类库,其github地址为:https://github.com/jstedfast/MailKit

一般情况下,MailKit都工作的很好,但可能是姿势不对,在发送附件时,只要附件名为中文名,接收方接收到的附件名必然是乱码或者tcmime.xx.xx.xx.bin 这种完全不明觉厉的东东(具体会乱码还是显示tcmime跟文件名长度有关),作为对于邮件协议不明觉厉,仅仅只是想要发封邮件的使用方,对此完全措手无策,幸好万能的互联网已经有了这个问题的解决方案,所以此处对发送邮件及附件这个过程进行了封装并予以记录

    using MailKit.Net.Smtp;
    using MimeKit;
    using MimeKit.Text;
    /// <summary>
    /// 基于MailKit的邮件帮助类
    /// </summary>
    public static class EMailHelper
    {
        /// <summary>
        /// 邮件服务器Host
        /// </summary>
        public static string Host { get; set; }
        /// <summary>
        /// 邮件服务器Port
        /// </summary>
        public static int Port { get; set; }
        /// <summary>
        /// 邮件服务器是否是ssl
        /// </summary>
        public static bool UseSsl { get; set; }
        /// <summary>
        /// 发送邮件的账号友善名称
        /// </summary>
        public static string UserName { get; set; }
        /// <summary>
        /// 发送邮件的账号地址
        /// </summary>
        public static string UserAddress { get; set; }
        /// <summary>
        /// 发现邮件所需的账号密码
        /// </summary>
        public static string Password { get; set; }

        /// <summary>
        /// 发送电子邮件,默认发送方为<see cref="UserAddress"/>
        /// </summary>
        /// <param name="subject">邮件主题</param>
        /// <param name="content">邮件内容主题</param>
        /// <param name="toAddress">接收方信息</param>
        /// <param name="textFormat">内容主题模式,默认TextFormat.Text</param>
        /// <param name="attachments">附件</param>
        /// <param name="dispose">是否自动释放附件所用Stream</param>
        /// <returns></returns>
        public static async Task SendEMailAsync(string subject, string content, IEnumerable<MailboxAddress> toAddress, TextFormat textFormat = TextFormat.Text, IEnumerable<AttachmentInfo> attachments = null, bool dispose = true)
        {
            await SendEMailAsync(subject, content, new MailboxAddress[] { new MailboxAddress(UserName, UserAddress) }, toAddress, textFormat, attachments, dispose).ConfigureAwait(false);
        }

        /// <summary>
        /// 发送电子邮件
        /// </summary>
        /// <param name="subject">邮件主题</param>
        /// <param name="content">邮件内容主题</param>
        /// <param name="fromAddress">发送方信息</param>
        /// <param name="toAddress">接收方信息</param>
        /// <param name="textFormat">内容主题模式,默认TextFormat.Text</param>
        /// <param name="attachments">附件</param>
        /// <param name="dispose">是否自动释放附件所用Stream</param>
        /// <returns></returns>
        public static async Task SendEMailAsync(string subject, string content, MailboxAddress fromAddress, IEnumerable<MailboxAddress> toAddress, TextFormat textFormat = TextFormat.Text, IEnumerable<AttachmentInfo> attachments = null, bool dispose = true)
        {
            await SendEMailAsync(subject, content, new MailboxAddress[] { fromAddress }, toAddress, textFormat, attachments, dispose).ConfigureAwait(false);
        }

        /// <summary>
        /// 发送电子邮件
        /// </summary>
        /// <param name="subject">邮件主题</param>
        /// <param name="content">邮件内容主题</param>
        /// <param name="fromAddress">发送方信息</param>
        /// <param name="toAddress">接收方信息</param>
        /// <param name="textFormat">内容主题模式,默认TextFormat.Text</param>
        /// <param name="attachments">附件</param>
        /// <param name="dispose">是否自动释放附件所用Stream</param>
        /// <returns></returns>
        public static async Task SendEMailAsync(string subject, string content, IEnumerable<MailboxAddress> fromAddress, IEnumerable<MailboxAddress> toAddress, TextFormat textFormat = TextFormat.Text, IEnumerable<AttachmentInfo> attachments = null, bool dispose = true)
        {
            var message = new MimeMessage();
            message.From.AddRange(fromAddress);
            message.To.AddRange(toAddress);
            message.Subject = subject;
            var body = new TextPart(textFormat)
            {
                Text = content
            };
            MimeEntity entity = body;
            if (attachments != null)
            {
                var mult = new Multipart("mixed")
                {
                    body
                };
                foreach (var att in attachments)
                {
                    if (att.Stream != null)
                    {
                        var attachment = string.IsNullOrWhiteSpace(att.ContentType) ? new MimePart() : new MimePart(att.ContentType);
                        attachment.Content = new MimeContent(att.Stream);
                        attachment.ContentDisposition = new ContentDisposition(ContentDisposition.Attachment);
                        attachment.ContentTransferEncoding = att.ContentTransferEncoding;
                        attachment.FileName = ConvertHeaderToBase64(att.FileName, Encoding.UTF8);//解决附件中文名问题
                        mult.Add(attachment);
                    }
                }
                entity = mult;
            }
            message.Body = entity;
            message.Date = DateTime.Now;
            using (var client = new SmtpClient())
            {
                //创建连接
                await client.ConnectAsync(Host, Port, UseSsl).ConfigureAwait(false);
                await client.AuthenticateAsync(UserAddress, Password).ConfigureAwait(false);
                await client.SendAsync(message).ConfigureAwait(false);
                await client.DisconnectAsync(true).ConfigureAwait(false);
                if (dispose && attachments != null)
                {
                    foreach (var att in attachments)
                    {
                        att.Dispose();
                    }
                }
            }
        }
        private static string ConvertToBase64(string inputStr, Encoding encoding)
        {
            return Convert.ToBase64String(encoding.GetBytes(inputStr));
        }
        private static string ConvertHeaderToBase64(string inputStr,Encoding encoding)
        {//https://www.cnblogs.com/qingspace/p/3732677.html
            var encode = !string.IsNullOrEmpty(inputStr) && inputStr.Any(c => c > 127);
            if (encode)
            {
                return "=?" + encoding.WebName + "?B?" + ConvertToBase64(inputStr, encoding) + "?=";
            }
            return inputStr;
        }
    }
    /// <summary>
    /// 附件信息
    /// </summary>
    public class AttachmentInfo : IDisposable
    {
        /// <summary>
        /// 附件类型,比如application/pdf
        /// </summary>
        public string ContentType { get; set; }
        /// <summary>
        /// 文件名称
        /// </summary>
        public string FileName { get; set; }
        /// <summary>
        /// 文件传输编码方式,默认ContentEncoding.Default
        /// </summary>
        public ContentEncoding ContentTransferEncoding { get; set; } = ContentEncoding.Default;
        /// <summary>
        /// 文件数组
        /// </summary>
        public byte[] Data { get; set; }
        private Stream stream;
        /// <summary>
        /// 文件数据流,获取数据时优先采用此部分
        /// </summary>
        public Stream Stream
        {
            get
            {
                if (this.stream == null && this.Data != null)
                {
                    stream = new MemoryStream(this.Data);
                }
                return this.stream;
            }
            set { this.stream = value; }
        }
        /// <summary>
        /// 释放Stream
        /// </summary>
        public void Dispose()
        {
            if (this.stream != null)
            {
                this.stream.Dispose();
            }
        }
    }
对于附件,此处定义了 AttachmentInfo 来作为附件的载体类,其支持两种方式进行附件上传:byte[]以及Stream,具体的使用例子如下
            EMailHelper.Host = "smtp.exmail.qq.com";
            EMailHelper.Port = 465;
            EMailHelper.UseSsl = true;
            EMailHelper.UserName = "你要展示的发送方名称";
            EMailHelper.Password = "你的邮箱密码";
            EMailHelper.UserAddress = "你的邮箱地址";
            var subject = "测试多个附件邮件";
            var content = "Just a test!";
            var attachs = new List<AttachmentInfo>();
            //从指定文件夹内读取要发送的附件
            foreach (var file in Directory.GetFiles("EMailAttach"))
            {
                var att = new AttachmentInfo
                {
                    FileName = Path.GetFileName(file),
                    //Data = File.ReadAllBytes(file)
                    Stream = File.OpenRead(file),//Data和Stream两种方式任意用一种即可
                    ContentTransferEncoding = ContentEncoding.Base64
                };
                attachs.Add(att);
            }
            await EMailHelper.SendEMailAsync(subject, content, new MailboxAddress[] {
                new MailboxAddress("接收方邮箱地址")
            }, attachments: attachs);

最后,如果要支持抄送和密送,那么只需要修改下上面的封装代码,支持Cc以及Bcc即可

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐