ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

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

2026/8/6 8:17:45 拓冰建站 浏览量
【.Net 6.0--通用帮助类--EmailHelper】

前言

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

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

邮箱类型SMTP-服务器地址SMTP-端口号POP-服务器地址POP-端口号是否SSL
163邮箱smtp.163.com25pop.163.com110
126邮箱smtp.126.com25pop.126.com110
139邮箱smtp.139.com25pop.139.com110
QQ邮箱smtp.qq.com25pop.qq.com110
QQ企业邮箱smtp.exmail.qq.com587/465pop.exmail.qq.com995
Gmail邮箱smtp.gmail.com587pop.gmail.com995
Foxmail邮箱smtp.foxmail.com25pop.foxmail.com110
Sina邮箱smtp.sina.com.cn25pop3.sina.com.cn110
SinaVIP邮箱smtp.vip.sina.com25pop3.vip.sina.com110
Sohu邮箱smtp.sohu.com25pop3.sohu.com110
Yahoo邮箱smtp.mail.yahoo.com.cn587pop.mail.yahoo.com.cn995

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

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

代码示例

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;}}
}
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; }}
}