Asp.net core 学习笔记 ( Smtp and Razor template 电子邮件和 Razor 模板 )
2020-12-28
hotmail 和 gmail 参考 :
如果 send 的时候出现 error 比如类似 :
The SMTP server requires a secure connection or the client was not authenticated. The server response was: 5.7.57 SMTP; Client was not authenticated t
o send anonymous mail during MAIL FROM [SG2P153CA0043.APCP153.PROD.OUTLOOK.COM]
那多半是下面几个问题
gmail 一般上需要去 account bypass less secure apps, 有时候 bypass 了不可以可能是 cache 问题, 去 clear cache. 还是不可以的话可能需要搞 app password 之类的 (我没试过这个). 总之 gmail 超麻烦
hotmail 好一点,要确保 email active (binding contact number), 而且不可以有 two factory 设置.
还有就是 ssl 一定要 enable 咯, port 587, UseDefaultCredentials = false, TLS 1.2 或以上 (2022年 2 月 不支持 TLS 1.0, 1.1 了)
live.com 的 smtp 是 smtp.live.com (更新: 2022-05-21 smtp.live.com 已经废弃了, 改用 smtp.office365.com)
hotmail 的是 smtp.office365.com
gmail 的是 smtp.gmail.com
遇到 error 如果是 account 的问题, google 和微软是会发 email 告诉你的. 所以我们要确保 password 对, host, port 对.
refer :
https://dotnetcoretutorials.com/2017/08/20/sending-email-net-core-2-0/
https://ppolyzos.com/2016/09/09/asp-net-core-render-view-to-string/
https://github.com/aspnet/Entropy/blob/dev/samples/Mvc.RenderViewToString/RazorViewToStringRenderer.cs ( 这个很干净, 没有依赖 http request )
直接看代码
要使用 Razor 模板需要提供这 2 个 服务
public void ConfigureServices(IServiceCollection services) { services.AddSingleton<ICompositeViewEngine, CompositeViewEngine>(); services.AddSingleton<IActionContextAccessor, ActionContextAccessor>(); }
Controller 注入相关服务
public class EmailController : Controller { public EmailController( IOptionsSnapshot<Configuration.Email> emailOptionsAccessor, ICompositeViewEngine compositeViewEngine, IActionContextAccessor actionContextAccessor ) { emailConfig = emailOptionsAccessor.Value; this.compositeViewEngine = compositeViewEngine; actionContext = actionContextAccessor.ActionContext; } private Configuration.Email emailConfig { get; set; } private ICompositeViewEngine compositeViewEngine { get; set; } private ActionContext actionContext { get; set; } }
最后呢
SmtpClient client = new SmtpClient { EnableSsl = emailConfig.enableSsl, Port = emailConfig.port, Host = emailConfig.host, UseDefaultCredentials = false, Credentials = new NetworkCredential(emailConfig.username, emailConfig.password) }; string body; using (StringWriter sw = new StringWriter()) { EmailTemplateViewmodel model = new EmailTemplateViewmodel { value = "dada" }; ViewData.Model = model; ViewEngineResult viewResult = compositeViewEngine.GetView( null, "~/Email/EmailTemplate.cshtml", false ); ViewContext viewContext = new ViewContext(actionContext, viewResult.View, ViewData, TempData, sw, new HtmlHelperOptions()); await viewResult.View.RenderAsync(viewContext); body = sw.GetStringBuilder().ToString(); } MailMessage mailMessage = new MailMessage { From = new MailAddress(emailConfig.from, emailConfig.displayName), Subject = "subject", Body = body, IsBodyHtml = true }; mailMessage.To.Add("hengkeat87@gmail.com"); await client.SendMailAsync(mailMessage);
上面的依赖当前的请求
如果要不依赖请求的
注入
IServiceProvider serviceProvider,
ITempDataProvider tempDataProvider
private async Task<string> GenerateBodyFromTemplateAsync(string templatePath, object model) { string body; using (StringWriter sw = new StringWriter()) { // 这里渲染模板是不包含任何 http 请求的东西的, 所以模板里请不要使用 http 的东西哦 var httpContext = new DefaultHttpContext(); httpContext.RequestServices = ServiceProvider; var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor()); var viewData = new ViewDataDictionary(metadataProvider: new EmptyModelMetadataProvider(), modelState: new ModelStateDictionary()); viewData.Model = model; var data = new TempDataDictionary(actionContext.HttpContext, TempDataProvider); var viewResult = CompositeViewEngine.GetView(null, templatePath, false); var viewContext = new ViewContext(actionContext, viewResult.View, viewData, data, sw, new HtmlHelperOptions()); await viewResult.View.RenderAsync(viewContext); body = sw.GetStringBuilder().ToString(); } return body; }