.NET Core使用FluentEmail发送邮件

前言

    在实际的项目开发中,我们会遇到许多需要通过程序发送邮件的场景,比如异常报警、消息、进度通知等等。一般情况下我们使用原生的SmtpClient类库居多,它能满足我们绝大多数场景。但是使用起来不够简洁,许多场景需要我们自行封装方法去实现,而且代码量非常可观。庆幸的是,我们有一款非常棒的组件,能满足我们绝大多数应用场景,而且使用简单功能强大,就是我们今天要说的FluentEmail,这也是我们实际在项目中正在使用的邮件发送组件。如果你们在.Net Core中有发送邮件的需求,也推荐去尝试一下。

FluentEmail

    FluentEmail是一款在GitHub上开源免费的支持.Net和.Net Core邮件发送组件,目前已有1K多的Star,而且近两年随着.Net Core的日益成熟,它的Star增长趋势还是非常迅猛的。它在GitHub地址是https://github.com/lukencode/FluentEmail,它的功能非常强大而且非常实用,支持Razor的邮件模板和支持使用SendGrid,MailGun,SMTP发送邮件,而且使用也非常简单。

Nuget组件

FluentEmail功能强大,而且对不同场景的支持都有独立的Nuget包,这种低耦合的拆分不仅使得依赖非常清晰,而且避免引入不需要的代码,具体功能包含在以下的组件包中

  • FluentEmail.Core - 基础核心包,包含了基础的模型定义和默认的设置,而且以下的引用包都包含了这个核心包。

  • FluentEmail.Smtp - 使用SMTP服务发送邮件的程序包。

  • FluentEmail.Razor - 通过Razor模板生成邮件发送内容。

  • FluentEmail.Mailgun - 使用Mailgun的Rest接口发送邮件。

  • FluentEmail.SendGrid - 使用SendGrid接口发送邮件。

  • FluentEmail.Mailtrap - 发送邮件Mailtrap, 使用的是FluentEmail.Smtp包进行发送.

  • FluentEmail.MailKit - 使用MailKit邮件库发送邮件。

普通邮件方式

接下来我们就演示一下如何使用FluentEmail发送邮件,由于我们实际业务中大多数都使用的SMTP的方式发送邮件,所以我们就以此为做演示,首先我们在项目中引入FluentEmail.Smtp包,目前最新版本为2.8.0

<PackageReference Include="FluentEmail.Smtp" Version="2.8.0" />

接下来我们就可以愉快的写代码了,它的编码使用方式非常简单而且非常简洁,主要通过链式编程的方式

//如果使用smtp服务发送邮件必须要设置smtp服务信息
SmtpClient smtp = new SmtpClient
{//smtp服务器地址(我这里以126邮箱为例,可以依据具体你使用的邮箱设置)Host = "smtp.126.com",UseDefaultCredentials = true,DeliveryMethod = SmtpDeliveryMethod.Network,//这里输入你在发送smtp服务器的用户名和密码Credentials = new NetworkCredential("邮箱用户名", "邮箱密码")
};
//设置默认发送信息
Email.DefaultSender = new SmtpSender(smtp);
var email = Email//发送人.From("zhangsan@126.com")//收件人.To("lisi@qq.com")//抄送人.CC("admin@126.com")//邮件标题.Subject("邮件标题")//邮件内容.Body("邮件内容");
//依据发送结果判断是否发送成功
var result = email.Send();
//或使用异步的方式发送
//await email.SendAsync();
if (result.Successful)
{//发送成功逻辑
}
else
{//发送失败可以通过result.ErrorMessages查看失败原因
}

如果你发送的内容中包含html格式的内容可以使用如下方式

var email = Email//发送人.From("zhangsan@126.com")//收件人.To("lisi@qq.com")//抄送人.CC("admin@126.com")//邮件标题.Subject("邮件标题")//只需要额外设置第二个参数为true即可.Body("<h1 align=\"center\">.NET大法好</h1><p>是的,这一点毛病都没有</p>",true);
//发送
var result = email.Send();

这个我们通过点击查看Body的方法声明即可得知第二个参数是用来表示内容是否为html格式,默认为false

IFluentEmail Body (string body, bool isHtml = false);

如果邮件的收件人为多个邮箱地址的话,可以采用To方法的另一个重载方法可以接受List<FluentEmail.Core.Models.Address>

var email = Email//发送人.From("zhangsan@126.com")//邮件标题.Subject("邮件标题")//邮件内容.Body("<h1 align=\"center\">.NET大法好</h1><p>是的,一点毛病都没有</p>",true);//构建多个接收人邮箱
string toUserStr = "oldwang@126.com;xiaoming@163.com;xiaoli@qq.com";
List<FluentEmail.Core.Models.Address> toUsers = toUserStr.Split(";").Select(i => new FluentEmail.Core.Models.Address { EmailAddress = i }).ToList();
//支持传入Address集合
email.To(toUsers)
//抄送人集合
.CC(toUsers);
//发送
var result = email.Send();

如果我们需要在发送的邮件中添加一个附件的话,可以使用Attache方法添加附件

var email = Email//发送人.From("zhangsan@qq.com")//收件人.To("lisi@126.com")//抄送人.CC("admin@126.com")//邮件标题.Subject("关于.Net Core怎么样")//邮件内容.Body("<h1 align=\"center\">.NET Core</h1><p>.Net Core很优秀吗?是的,一点毛病都没有!!!</p>",true);//构建附件
var stream = new MemoryStream();
var sw = new StreamWriter(stream);
sw.WriteLine("您好,这是文本里的内容");
sw.Flush();
stream.Seek(0, SeekOrigin.Begin);
var attachment = new FluentEmail.Core.Models.Attachment
{Data = stream,ContentType = "text/plain",Filename = "Hello.txt"
};
//添加附件
email.Attach(attachment);
var result = email.Send();

如果需要添加多个附件的话Attach方法支持传入Attachment集合

//构建附件
var stream = new MemoryStream();
var sw = new StreamWriter(stream);
sw.WriteLine("您好,这是文本里的内容");
sw.Flush();
stream.Seek(0, SeekOrigin.Begin);
//附件1
var attachment = new FluentEmail.Core.Models.Attachment
{Data = stream,ContentType = "text/plain",Filename = "Hello.txt"
};//附件2
var attachment2 = new FluentEmail.Core.Models.Attachment
{Data = File.OpenRead(@"D:\test.txt"),ContentType = "text/plain",Filename = "test.txt"
};//添加附件
email.Attach(new List<FluentEmail.Core.Models.Attachment> { attachment, attachment2 });
var result = email.Send();

使用Razor模板

    上面的内容我们介绍了使用FluentEmail使用常规的方式发送邮件,但是有时候我们需要发送一些内容是动态的或者发送一些样式比较复杂html网页内容。通常我们使用原生的SmptClient的时候都是通过拼接html代码方式,但是这种方式相对来说比较费时费力,对于.Net程序员来说Razor引擎是我们构建动态html页面最熟悉的方式,而FluentEmail正是为我们提供了Razor模板的支持。首先,我们在之前的基础上引入FluentEmail.Razor模板支持组件

<PackageReference Include="FluentEmail.Razor" Version="2.8.0" />

由于ASP.NET Core2.2开始默认是使用的视图编译功能,视图会编译成 项目名称.Views.dll,但是FluentEmail.Razor又需要读取视图文件的内容,所以要在csproj文件中添加以下内容

<MvcRazorExcludeRefAssembliesFromPublish>true</MvcRazorExcludeRefAssembliesFromPublish>

然后我们就可以使用Razor模板生成邮件内容,具体的使用方式

//声明使用razor的方式
Email.DefaultRenderer = new RazorRenderer();
//razor内容
var template = "你好@Model.Name先生, 请核实您的电话号码是否为@Model.Phone";
var email = Email.From("lisi@126.com").To("zhangsan@qq.com").Subject("手机号核实")//传递自定义POCO类//.UsingTemplate<UserInfo>(template, new UserInfo { Name = "张三", Phone吗 = "100110119120" })//或传递匿名对象.UsingTemplate(template, new { Name = "张三", Phone吗 = "100110119120" });
var result = await email.SendAsync();

当然它支持的方式不仅仅只是Razor字符串,还可以传递Razor视图文件

var email = Email.From("lisi@126.com").To("zhangsan@qq.com").Subject("手机号核实")//传递自定义POCO类//.UsingTemplateFromFile<UserInfo>($"{Directory.GetCurrentDirectory()}/template.cshtml", //     new UserInfo { Name = "张三", Phone吗 = "100110119120" });//第一个参数为视图文件位置,第二个参数为模型对象.UsingTemplateFromFile($"{Directory.GetCurrentDirectory()}/template.cshtml", new { Name = "张三", Phone吗 = "100110119120" });
var result = await email.SendAsync();

FluentEmail.Razor之所以能够支持强大的Razor模板引擎,主要是得益于它内部集成了RazorLight,这是一款非常强大的Razor引擎,可以将Razor模板字符串或者Razor视图文件解析成具体的字符串结果,具体详情可参阅RazorLight官方GitHub地址https://github.com/toddams/RazorLight,目前正式版并不支持.Net Core,可以选择下载beta版本

Install-Package RazorLight -Version 2.0.0-beta10

它的使用方式也非常简单

//razor字符串的方式
var engine = new RazorLightEngineBuilder().UseEmbeddedResourcesProject(typeof(Program)).UseMemoryCachingProvider().Build();
string template = "Hello, @Model.Name. Welcome to RazorLight repository";
ViewModel model = new ViewModel {Name = "John Doe"};
//result就是解析后的字符串
string result = await engine.CompileRenderStringAsync("templateKey", template, model);

或使用razor视图文件的方式

var engine = new RazorLightEngineBuilder().UseFileSystemProject("${Directory.GetCurrentDirectory()}").UseMemoryCachingProvider().Build();
var model = new {Name = "John Doe"};
string result = await engine.CompileRenderAsync("template.cshtml", model);

当然它支持的方式不仅仅只有这两种,无论是使用便捷程度还是功能上都非常的强大,有兴趣的同学可以自行查阅RazorLight的GitHub地址,讲解的还是非常详细的。在这里就不在过多的讨论关于RazorLight的使用方式了。
    关于发送的邮件内容,这里有一个非常重要的点需要友情提示一下公共邮箱运营商比如网易或腾讯,有的可能需要手动开启SMTP服务,具体如何设置可以参考https://blog.csdn.net/c13_tianming/article/details/47660635一文。还有一点也比较重要如果你使用公共邮箱运营商的邮箱那么他们会对邮件的标题和内容限制比较大,可能出现的问题比较多,而且开启Smtp服务需要发送短信认证才能开启。好在大部分公司都有自己的邮件系统,在实际发送邮件的过程中可能不会存在这么多的问题。

结合依赖注入使用

在使用.Net Core的实际开发中,依赖注入已经成为了必不可少的开发模式。如果你正在使用.Net Core开发项目,但是你还没有接触依赖注入,那么需要你先自行反省一下。FluentEmail作为一款与时俱进的组件,也可以结合依赖注入使用,使用这种方式我们可以在注册的时候统一的配置一些默认的设置。这波操作就不需要额外引入一些别的包了,如果你需要使用Smtp就引入FluentEmail.Smtp包,如果你需要使用Razor模板就引入FluentEmail.Razor包,关于注入的这一部分的功能其实是包含在FluentEmail.Core包里面的

public void ConfigureServices(IServiceCollection services)
{SmtpClient smtp = new SmtpClient{//smtp服务器地址(我这里以126邮箱为例,可以依据具体你使用的邮箱设置)Host = "smtp.qq.com",UseDefaultCredentials = true,DeliveryMethod = SmtpDeliveryMethod.Network,//这里输入你在发送smtp服务器的用户名和密码Credentials = new NetworkCredential("zhangsan@qq.com", "zhangsan")};//注入的时候可以添加一些默认的设置services//设置默认发送用户.AddFluentEmail("zhangsan@qq.com")//添加razor模板支持//.AddRazorRenderer($"{Directory.GetCurrentDirectory()}/Views").AddRazorRenderer()//配置默认的smtp服务信息.AddSmtpSender(smtp);
}

在需要发送邮件的类中直接注入IFluentEmail,不必惊慌咱们上面使用的Email这个类其实就是实现了IFluentEmail这个接口,所以使用方式上是完全一致的

public async Task<IActionResult> SendEmail([FromServices]IFluentEmail email)
{var result = await email//发送人//发送人.From("zhangsan@126.com")//收件人.To("lisi@qq.com")//抄送人.CC("admin@126.com")//邮件标题.Subject("邮件标题")//邮件内容.Body("邮件内容").SendAsync();return View();
}

如果你需要发送Razor视图模板相关的内容,也还是那个熟悉的配方那个熟悉的味道,没有任何的不同,只是省略了一些我们在注册的时候添加的一些默认配置

public async Task<IActionResult> SendEmail([FromServices]IFluentEmail email)
{var template = "你好@Model.Name先生, 请核实您的电话号码是否为@Model.Phone";var result = await email//发送人.From("lisi@126.com").To("zhangsan@qq.com").Subject("手机号核实")//传递自定义POCO类//.UsingTemplate<UserInfo>(template, new UserInfo { Name = "张三", Phone吗 = "100110119120" })//或传递匿名对象.UsingTemplate(template, new { Name = "张三", Phone吗 = "100110119120" }).SendAsync();return View();
}

总结

    关于FluentEmail的基本使用方式我们就介绍到这里,我个人感觉它自身的功能还是非常强大的,而且使用起来非常的简单。说实话在之前我没接触到FluentEmail之前,我经常在园子里看到其他语言集成发送邮件的组件,确实非常强大,比如在springboot中集成spring-boot-starter-mail真的是非常的便捷。后来无意中接触到了FluentEmail心里还是蛮欣慰的,一是它强大的功能和易用性,其次是可以去结合.Net Core进一步优化了它的使用方式,至少在.Net和.Net Core中我们也拥有一款非常便捷的邮件发送组件。FluentEmail的作者也呼吁更多的开发者能够了解并参与到FluentEmail开发和实践中去,最后再次贴上它的GitHub地址https://github.com/lukencode/FluentEmail,有兴趣的可以去了解学习一下顺便别忘了给个Star。

????欢迎扫码关注我的公众号????

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

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

相关文章

进击吧! Blazor !第四期 组件开发

Blazor 是一个 Web UI 框架&#xff0c;可通过 WebAssembly 在任意浏览器中运行 .Net 。Blazor 旨在简化快速的单页面 .Net 浏览器应用的构建过程&#xff0c;它虽然使用了诸如 CSS 和 HTML 之类的 Web 技术&#xff0c;但它使用 C&#xff03;语言和 Razor 语法代替 JavaScrip…

HttpReports 2.0 发布了 !!!

https://www.cnblogs.com/myshowtime/p/13806631.html来源???? 前言介绍HttpReports 是基于.Net Core 开发的APM监控系统&#xff0c;使用MIT开源协议&#xff0c;主要功能包括&#xff0c;统计, 分析, 可视化&#xff0c; 监控&#xff0c;追踪等&#xff0c;适合在微服务…

.NET Standard 来日苦短去日长

作者&#xff1a;Richard翻译&#xff1a;精致码农-王亮原文&#xff1a;http://dwz.win/Q4h自从 .NET 5 宣贯以来&#xff0c;很多人都在问这对 .NET Standard 意味着什么&#xff0c;它是否仍然重要。在这篇文章中&#xff0c;我将解释 .NET 5 是如何改进代码共用并取代 .NET…

leetcode538. 把二叉搜索树转换为累加树

一:题目 二:上码 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val val; }* TreeNode(int val, TreeNode left, TreeNode right) {* …

【BCVP升级】泛型主键的使用

&#xff08;图片来源于SqlSugar官网&#xff0c;5年5.0&#xff09;大家假期已经结束了吧&#xff0c;还有80天左右就要到2021年了&#xff0c;你准备好了么&#xff1f;BCVP&#xff08;Blog.Core&Vue Project&#xff09;项目已经开源2年多&#xff0c;从来没有停更过&a…

leetcode404. 左叶子之和(迭代和递归)

一:题目 二:上码 迭代 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val val; }* TreeNode(int val, TreeNode left, TreeNode right…

Dotnet Core使用特定的SDKRuntime版本

Dotnet Core的SDK版本总在升级&#xff0c;怎么使用一个特定的版本呢&#xff1f;假期过完了&#xff0c;心情还在。今天写个短的。一、前言写这个是因为昨天刷微软官方文档&#xff0c;发现global.json在 SDK 3.0 后&#xff0c;更新了一些内容。文档提到了这个更新&#xff0…

Spring中IOC的理解(通俗易懂版)

文章目录1.IOC提出背景2:IOC的核心概念3:IOC的实现方式4:IOC的入门案例(1):思路分析(2):代码解析5:DI入门案例(1):思路分析(2):代码解析6:DI依赖注入的方式(1):前言(2):Set方式注入(3):构造器注入(4):依赖的自动装配7:注解开发模式的依赖注入(1):前言介绍(2):注解模式的依赖注入…

首个使用Blazor 技术实现的社区软件 BlazorCommunity 发布

BlazorCommunity 是首个使用Blazor 实现的开源社区软件&#xff0c; 其组件基于Element-Blazor &#xff0c; Element-Blazor 是一个 API 模仿 Element&#xff0c;CSS 直接使用 Element 样式&#xff0c;HTML 结构直接使用 Element HTML 结构 的 Web开发库。由于基于了…

leetcode112. 路径总和

一:题目 二:上码 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val val; }* TreeNode(int val, TreeNode left, TreeNode right) {* …

全球顶级开源大神们现身 COSCon'20

点击上方“开源社”关注我们| 作者&#xff1a;Will Wang| 编辑&#xff1a;沈于蓝| 责编&#xff1a;王皓月业界最具影响力的开源年度盛会2020中国开源年会 (COSCon20) 将于 10月24-25日由开源社举办。COSCon 以其独特定位及日益增加的影响力&#xff0c;吸引越来越多的顶级企…

做.NET开发多年,公司要我转Java...

10月13日&#xff0c;.NET5发布了(Release Candidate)RC2版本&#xff0c;包含语言新版本C#9和F#5等&#xff0c;这是正式版前的最后更新&#xff01;终于&#xff0c;万众期待的.NET5真的要来了&#xff01;公司让我转Java&#xff0c;我成功说服老板&#xff01;机会永远留给…

ASP.NET Core Blazor WebAssembly 之 .NET JavaScript互调

Blazor WebAssembly可以在浏览器上跑C#代码&#xff0c;但是很多时候显然还是需要跟JavaScript打交道。比如操作dom&#xff0c;当然跟angular、vue一样不提倡直接操作dom&#xff1b;比如浏览器的后退导航。反之JavaScript也有可能需要调用C#代码来实现一些功能&#xff0c;毕…

leetcode654. 最大二叉树

一:上码 二:上码 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val val; }* TreeNode(int val, TreeNode left, TreeNode right) {* …

浅议C#客户端和服务端通信的几种方法:Rest和GRPC和其他

本文来自&#xff1a;https://michaelscodingspot.com/rest-vs-grpc-for-asp-net/浅议C#客户端和服务端通信的几种方法&#xff1a;Rest和GRPC在C&#xff03;客户端和C&#xff03;服务器之间进行通信的方法有很多。一些功能强大&#xff0c;而其他功能则不是很多。有些非常快…

leetcode106. 从中序与后序遍历序列构造二叉树(java详解版)

一:题目 二:上码 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val val; }* TreeNode(int val, TreeNode left, TreeNode right) {* …

COSCon’20开源教育论坛介绍

点击上方“开源社”关注我们| 作者&#xff1a;周添一| 编辑&#xff1a;沈于蓝| 设计&#xff1a;冯艺怡| 责编&#xff1a;王皓月论坛简介在当今数据驱动的智能社会&#xff0c;软件作为数字智能社会的数据基础设施&#xff0c;承载了社会的高效运转。在这个软件定义世界的潮…

leetcode105. 从前序与中序遍历序列构造二叉树

一:题目 二:上码 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val val; }* TreeNode(int val, TreeNode left, TreeNode right) {* …

想进BAT等大厂,到底要怎么做?

职场&认知洞察 丨 作者 / findyi这是findyi公众号的第82篇原创文章最近我的公众号多了很多学生读者&#xff0c;很多人问我&#xff1a;如果要进BAT等大厂&#xff0c;我是应该直接工作还是考研&#xff1f;对于未来要从事程序员行业的朋友来说&#xff0c;要不要考研&…

.NET 5.0 RC 2 发布,正式版将在 11 月 .NET Conf 大会上发布

原文&#xff1a;http://dwz.win/ThX作者&#xff1a;Richard翻译&#xff1a;精致码农-王亮说明&#xff1a;1. 本译文舍弃了少许我实在不知道如何翻译但又不是很重要的语句。2. 本文有不少超链接&#xff0c;由于微信公众号和头条平台外链会被剔除 URL 地址&#xff0c;所以原…