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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/225141.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

(C语言)精确计算程序运行时间的方法

一、先计算每秒多少个计数 typedef __int64 s64;s64 tps; /* timestamp counter per second */s64 get_tps(void) {s64 t0 rdtsc();Sleep(100);return (rdtsc() - t0) * 10; } 这段代码定义了一个函数 get_tps&#xff0c;该函数用于测量处理器的时间戳计数器&#xff08;RD…

【答案】2023年国赛信息安全管理与评估第三阶段夺旗挑战CTF(网络安全渗透)

【答案】2023年国赛信息安全管理与评估第三阶段夺旗挑战CTF&#xff08;网络安全渗透&#xff09; 全国职业院校技能大赛高职组信息安全管理与评估 &#xff08;赛项&#xff09; 评分标准 第三阶段 夺旗挑战CTF&#xff08;网络安全渗透&#xff09; *竞赛项目赛题* 本文…

柔性数组(结构体成员)

目录 前言&#xff1a; 柔性数组&#xff1a; 给柔性数组分配空间&#xff1a; 调整柔性数组大小&#xff1a; 柔性数组的好处&#xff1a; 前言&#xff1a; 柔性数组&#xff1f;可能你从未听说&#xff0c;但是确实有这个概念。听名字&#xff0c;好像就是柔软的数…

如何连接到 Azure SQL 数据库(下)

在《如何连接到 Azure SQL 数据库&#xff08;上&#xff09;》中&#xff0c;我们已经了解到了以下内容↓↓↓ 开始之前&#xff1a;Azure 连接凭据和防火墙 如何检索 Azure 连接凭据如何配置服务器防火墙使用 SQL Server Management Studio 连接到 Azure使用 dbForge Studio…

数据结构--稀疏矩阵及Java实现

一、稀疏 sparsearray 数组 1、先看一个实际的需求 编写的五子棋程序中&#xff0c;有存盘退出和续上盘的功能。 分析问题: 因为该二维数组的很多值是默认值 0, 因此记录了很多没有意义的数据.->稀疏数组。 2、稀疏数组基本介绍 当一个数组中大部分元素为&#xff10;…

wordpress安装之正式开始安装wordpress

1、拉取wordpress镜像 docker pull wordpress 2、启动容器 启动容器&#xff0c;设置容器名为wordpress2并把80端口映射到宿主机的9988端口 docker run -it --name wordpress2 -p 9988:80 -d wordpress 3、查看容器状态 docker ps 4、安装wordpress博客程序 因为我们前面启…

微信小程序---使用npm包安装Vant组件库

在小程序项目中&#xff0c;安装Vant 组件库主要分为如下3步: 注意&#xff1a;如果你的文件中不存在pakage.json&#xff0c;请初始化一下包管理器 npm init -y 1.通过 npm 安装(建议指定版本为1.3.3&#xff09; 通过npm npm i vant/weapp1.3.3 -S --production 通过y…

大数据技术14:FlinkCDC数据变更捕获

前言&#xff1a;Flink CDC是Flink社区开发的flink-cdc-connectors 组件&#xff0c;这是⼀个可以直接从 MySQL、PostgreSQL 等数据库直接读取全量数据和增量变更数据的 source 组件。 https://github.com/ververica/flink-cdc-connectors 一、CDC 概述 CDC 的全称是 Change …

换内核ubuntu

grep menuentry /boot/grub/grub.cfg我要使用第三个(索引从0开始&#xff0c;所以是第二个) 可以使用vi编辑&#xff08;很麻烦&#xff09; i变为插入模型 esc变为普通模型 &#xff1a;x删除单个字符&#xff0c;dd删除一行&#xff0c;&#xff1a;wq保存并退出 更新文件…

rabbitmq-windows安装使用-简易后台界面-修改密码

文章目录 1.下载2.安装3.安装 RabbitMQ4.后台访问5.修改密码 1.下载 将erlang运行时和rabbitmq-windows版本&#xff0c;上传在csdn&#xff0c;下载链接。https://download.csdn.net/download/m0_67316550/88633443 2.安装 右键&#xff0c;以管理员身份运行rabbitmq。启动…

Android 12.0 Launcher3定制化之动态时钟图标功能实现

1.概述 在12.0的系统产品rom定制化开发中,在Launcher3中的定制化的一些功能中,对于一些产品要求需要实现动态时钟图标功能,这就需要先绘制时分秒时针表盘,然后 每秒刷新一次时钟图标,时钟需要做到实时更新,做到动态时钟的效果,接下来就来分析这个功能的实现 如图: 2.动…

《Kotlin核心编程》笔记:面向对象

kotlin 中的类 // Kotlin中的一个类 class Bird {val weight: Double 500.0val color: String "blue"val age: Int 1fun fly() { } // 全局可见 }把上述代码反编译成Java的版本&#xff0c;然后分析它们具体的差异&#xff1a; public final class Bird {privat…

Linux部署MySQL5.7和8.0版本 | CentOS和Ubuntu系统详细步骤安装

一、MySQL数据库管理系统安装部署【简单】 简介 MySQL数据库管理系统&#xff08;后续简称MySQL&#xff09;&#xff0c;是一款知名的数据库系统&#xff0c;其特点是&#xff1a;轻量、简单、功能丰富。 MySQL数据库可谓是软件行业的明星产品&#xff0c;无论是后端开发、…

【产品经理】产品专业化提升路径

产品专业化就是上山寻路&#xff0c;梳理一套作为产品经理的工作方法。本文作者从设计方法、三基座、专业强化、优秀产品拆解、零代码这五个方面&#xff0c;对产品经理的产品专业化进行了总结归纳&#xff0c;一起来看一下吧。 产品专业化就是上山寻路&#xff0c;梳理一套作为…

Zlmediakit 接收到 rtc包后的处理流程

客户端通过rtc 推流&#xff08;视频为h264&#xff09;到 ZlmediaKit 时&#xff0c;ZlmediaKit收到包后&#xff0c;到进行rtp 包排序的流程堆栈&#xff0c;方便了解逻辑 #0 mediakit::RtspMediaSourceImp::onWrite (this0x7fffd0009d68, rtp..., key_posfalse) at /root/…

数据结构 | Log-Structured Merge Tree (LSM Tree)

今天介绍LSM Tree这个数据结构&#xff0c;严格意义上来说&#xff0c;他并不像他的名字一样是一棵树型的数据结构&#xff0c;而更多是一种设计思想。 LSM Tree最先在1996年被提出&#xff0c;后来被广泛运用于现代NoSQL&#xff08;非关系型数据库&#xff09;系统中&#xf…

虚幻学习笔记17—C++委托(单播)

一、前言 相比“代理”这个名词我更喜欢叫“委托”&#xff0c;虚幻的委托分为三类&#xff0c;分别为单播、多播和动态多播。单播顾名思义就是一次只能绑定一个函数的委托&#xff0c;多播能一次性绑定多个&#xff0c;动态多播即可以在蓝图中进行动态的绑定且可以绑定多个。 …

mybatisplus使用雪花id通过swagger返回ID时精度丢失问题

在使用mybatisplus自带雪花的时候会发现返回的ID是19位的长度&#xff0c;因此在通过swagger页面展示的时候会发现后端返回的和页面展示的ID不一致问题。是因为精度丢失的问题。因此需要更改雪花ID的长度跟踪进去&#xff1a;发现是DefaultIdentifierGenerator类实现了Identifi…

蓝桥杯专题-真题版含答案-【扑克牌排列】【放麦子】【纵横放火柴游戏】【顺时针螺旋填入】

Unity3D特效百例案例项目实战源码Android-Unity实战问题汇总游戏脚本-辅助自动化Android控件全解手册再战Android系列Scratch编程案例软考全系列Unity3D学习专栏蓝桥系列ChatGPT和AIGC &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff0c;以及各种资源分…

【Redis】【MySQL】redis与mysql的慢查询

redis和mysql都存在对于慢查询的日志记录&#xff0c;下面将叙述一下两者的慢查询。 一&#xff0c;redis[1] redis的慢查询日志本质上是一个list对象&#xff0c;不过redis并没有提供慢查询日志的key。开发者可以通过下列命令查询慢查询日志&#xff1a; #获得慢查询日志&a…