【.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; }
    }
}
相关推荐
2401_840192279 分钟前
OpenStack基础架构
运维·服务器·openstack
墨楠。32 分钟前
数据结构学习记录-树和二叉树
数据结构·学习·算法
文城5211 小时前
Mysql存储过程(学习自用)
数据库·学习·mysql
HaoHao_0101 小时前
AWS Serverless Application Repository
服务器·数据库·云计算·aws·云服务器
我们的五年1 小时前
【C语言学习】:C语言补充:转义字符,<<,>>操作符,IDE
c语言·开发语言·后端·学习
励志去大厂的菜鸟2 小时前
系统相关类——java.lang.Math (三)(案例详细拆解小白友好)
java·服务器·开发语言·深度学习·学习方法
Icoolkj2 小时前
微服务学习-Nacos 注册中心实战
linux·学习·微服务
老王聊主机2 小时前
2025年华为云一键快速部署幻兽帕鲁联机服务器教程
运维·服务器·华为云
siy23332 小时前
【c语言日寄】Vs调试——新手向
c语言·开发语言·学习·算法
书生-w2 小时前
Redis Windows 解压版安装
数据库·windows·redis