【.Net 6.0--通用帮助类--EmailHelper】

前言

邮件帮助类(smtp协议),需要NuGet引用MailKit包,包含了同步发送邮件(SendEmail)、异步发送邮件( SendEmailAsync)方法,由于非企业邮箱每日有发送限额,故代码中支持轮询多个邮箱,当某个邮箱超限时,标记为不可用状态,当天不再使用,以确保邮件正常发送成功,同时支持多种邮箱类型,见下表。

下表为常用邮箱服务器的地址和端口(SMTP/POP)

邮箱类型 SMTP-服务器地址 SMTP-端口号 POP-服务器地址 POP-端口号 是否SSL
163邮箱 smtp.163.com 25 pop.163.com 110
126邮箱 smtp.126.com 25 pop.126.com 110
139邮箱 smtp.139.com 25 pop.139.com 110
QQ邮箱 smtp.qq.com 25 pop.qq.com 110
QQ企业邮箱 smtp.exmail.qq.com 587/465 pop.exmail.qq.com 995
Gmail邮箱 smtp.gmail.com 587 pop.gmail.com 995
Foxmail邮箱 smtp.foxmail.com 25 pop.foxmail.com 110
Sina邮箱 smtp.sina.com.cn 25 pop3.sina.com.cn 110
SinaVIP邮箱 smtp.vip.sina.com 25 pop3.vip.sina.com 110
Sohu邮箱 smtp.sohu.com 25 pop3.sohu.com 110
Yahoo邮箱 smtp.mail.yahoo.com.cn 587 pop.mail.yahoo.com.cn 995

代码中的email.json格式如下,请自行配置个人邮箱:

json 复制代码
[
	{
		"Host": "smtp.163.com",
		"EnableSsl": true,
		"Port": 465,
		"SendAddress": "xxxx@163.com",
		"LoginPassword": "邮箱登录密码",
		"Password": "smtp分配的密码,代码中使用此密码",
		"CanUse": true
	}
]

代码示例

C# 复制代码
using MailKit.Net.Smtp;
using MimeKit;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;
using VW.API.Common.Models;

namespace VW.API.Common.Utils
{
    /// <summary>
    /// EmailHelper 的摘要说明:邮件帮助类
    /// </summary>
    public class EmailHelper
    {
        private static readonly string _emailConfigPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Configs/email.json");

        /// <summary>
        /// 创建Email
        /// </summary>
        /// <param name="email">邮箱地址</param>
        /// <param name="subject">邮件主题</param>
        /// <param name="message">邮件内容</param>
        /// <param name="attachments">附件</param>
        /// <returns>Email</returns>
        private static SmtpClient GetSmtpClient(string email, string subject, string message, List<string> attachments, EmailModel emailModel, out MimeMessage mimeMessage)
        {
            try
            {
                var client = new SmtpClient();

                client.MessageSent += (sender, args) =>
                {
                    LogHelper.Error(args.Message.ToString());
                };

                client.ServerCertificateValidationCallback = (sender, certificate, certChainType, errors) => true;
                client.Connect(emailModel.Host, emailModel.Port, emailModel.EnableSsl);
                client.Authenticate(emailModel.SendAddress, emailModel.Password);
                
                mimeMessage = new MimeMessage();
                mimeMessage.From.Add(new MailboxAddress(emailModel.SendAddress, emailModel.SendAddress));
                mimeMessage.To.Add(new MailboxAddress(email, email));
                mimeMessage.Subject = subject;
                var builder = new BodyBuilder();
                builder.HtmlBody = message;
                foreach (var attachment in attachments)
                {
                    builder.Attachments.Add(attachment);
                }
                mimeMessage.Body = builder.ToMessageBody();
                
                return client;
            }
            catch (Exception) { throw; }
        }

        /// <summary>
        /// 发送邮件(同步)
        /// </summary>
        /// <param name="email">邮箱地址</param>
        /// <param name="subject">邮件主题</param>
        /// <param name="message">邮件内容</param>
        /// <param name="attachments">附件</param>
        /// <returns>bool</returns>
        public static bool SendEmail(string email, string subject, string message, List<string> attachments = null)
        {
            bool success = false;

            string lastDayFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"Configs/{DateTime.Now.AddDays(-1).ObjToDateSplitYMD()}.email.json");
            FileHelper.DeleteFile(lastDayFilePath);
            string todayFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"Configs/{DateTime.Now.ObjToDateSplitYMD()}.email.json");
            if (!FileHelper.IsExistFile(todayFilePath))
                FileHelper.Copy(_emailConfigPath, todayFilePath, true);

            List<EmailModel> emailModels = JsonConvert.DeserializeObject<List<EmailModel>>(FileHelper.FileToString(todayFilePath));
            foreach (EmailModel emailModel in emailModels)
            {
                if (!emailModel.CanUse)//不能使用
                    continue;

                try
                {
                    var client = GetSmtpClient(email, subject, message, attachments, emailModel, out MimeMessage mimeMessage);
                    client.Send(mimeMessage);
                    client.Disconnect(true);
                    //client.Dispose();

                    success = true;
                    break;
                }
                catch (Exception ex)
                {
                    LogHelper.Error(JsonConvert.SerializeObject(emailModel));
                    LogHelper.Error(ex.ToString());
                    emailModel.CanUse = false;
                    success = false;
                }
            }

            FileHelper.WriteText(todayFilePath, JsonConvert.SerializeObject(emailModels));

            return success;
        }

        /// <summary>
        /// 发送邮件(异步)
        /// </summary>
        /// <param name="email">邮箱地址</param>
        /// <param name="subject">邮件主题</param>
        /// <param name="message">邮件内容</param>
        /// <param name="attachments">附件</param>
        /// <returns>bool</returns>
        public static async Task<bool> SendEmailAsync(string email, string subject, string message, List<string> attachments)
        {
            bool success = false;

            string lastDayFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"Configs/{DateTime.Now.AddDays(-1).ObjToDateSplitYMD()}.email.json");
            FileHelper.DeleteFile(lastDayFilePath);
            string todayFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, $"Configs/{DateTime.Now.ObjToDateSplitYMD()}.email.json");
            if (!FileHelper.IsExistFile(todayFilePath))
                FileHelper.Copy(_emailConfigPath, todayFilePath, true);

            List<EmailModel> emailModels = JsonConvert.DeserializeObject<List<EmailModel>>(FileHelper.FileToString(todayFilePath));
            foreach (EmailModel emailModel in emailModels)
            {
                if (!emailModel.CanUse)//不能使用
                    continue;

                try
                {
                    var client = GetSmtpClient(email, subject, message, attachments, emailModel, out MimeMessage mimeMessage);
                    await client.SendAsync(mimeMessage);
                    client.Disconnect(true);
                    //client.Dispose();

                    success = true;
                    break;
                }
                catch (Exception ex)
                {
                    LogHelper.Error(JsonConvert.SerializeObject(emailModel));
                    LogHelper.Error(ex.ToString());
                    emailModel.CanUse = false;
                    success = false;
                }
            }

            FileHelper.WriteText(todayFilePath, JsonConvert.SerializeObject(emailModels));

            return success;
        }
    }
}
C# 复制代码
namespace VW.API.Common.Models
{
    /// <summary>
    /// EmailModel
    /// </summary>
    public class EmailModel
    {
        /// <summary>
        /// 主机地址
        /// </summary>
        public string Host { set; get; }
        /// <summary>
        /// 是否使用SSL
        /// </summary>
        public bool EnableSsl { set; get; }
        /// <summary>
        /// 端口号
        /// </summary>
        public int Port { set; get; }
        /// <summary>
        /// 邮件地址
        /// </summary>
        public string SendAddress { set; get; }
        /// <summary>
        /// 登录密码
        /// </summary>
        public string LoginPassword { set; get; }
        /// <summary>
        /// 邮件STMP授权码
        /// </summary>
        public string Password { set; get; }
        /// <summary>
        /// 是否可用
        /// </summary>
        public bool CanUse { set; get; }
    }
}
相关推荐
博洋科技1 分钟前
网站建设的服务器该如何选择?
运维·服务器·网站建设·保定响应式网站建设·保定h5网站建设·保定网站建设
人类群星闪耀时6 分钟前
服务器管理:从零开始的服务器安装与配置指南
运维·服务器
李小星同志33 分钟前
高级算法设计与分析 学习笔记6 B树
笔记·学习
霜晨月c1 小时前
MFC 使用细节
笔记·学习·mfc
小江湖19941 小时前
元数据保护者,Caesium压缩不丢重要信息
运维·学习·软件需求·改行学it
Crazy Struggle1 小时前
.NET 7+Angular 4 轻量级新零售进销存系统
.net·angular·进销存系统
dot.Net安全矩阵1 小时前
.NET内网实战:通过命令行解密Web.config
前端·学习·安全·web安全·矩阵·.net
河南宽信李工1503806 16862 小时前
测绘航空摄影专项资质在洛阳市的获取流程
服务器
微刻时光2 小时前
Redis集群知识及实战
数据库·redis·笔记·学习·程序人生·缓存
学习向前冲2 小时前
AD域控服务器
运维·服务器