Örnek projeyi github üzerinden indirmek veya görüntülemek için https://github.com/ayzdru/EmailTemplateWithRazorViewEngine adresine gidebilirsiniz.
Razor View Engine Nedir?

Razor Syntax (Sözdizimi) ile HTML, CSS, Javascript kodları içerisinde C# dilini kullanıp, render ettikten sonra render edilmiş çıktıyı almamıza yarayan altyapıdır.
Email Templatelerinde Razor View Engine kullanmamızın sebebi;
Şablon Emaillerde dinamik alanlar olabilir. Örneğin;
"Merhaba Ayaz" şeklinde gönderebiliriz.
burada Ayaz dinamik bir yazıdır. Bunu genellikle Ayaz yazan yere #FirstName# diye bir kelime yazıp, arka tarafta string.Replace methodunu kullanarak #FirstName# kelimesini değişkendeki değer ile değiştirmeye çalışıyoruz. Razor View Engine ile @Model.FirstName şeklinde kullanarak hem kolaylık ve hız, hemde Layoutları kullanabiliyoruz.
SMTP (Simple Mail Transfer Protokol) Nedir?
Elektronik posta gönderme protokolü, bir email göndermek için server ile client arasındaki iletişim şeklini belirleyen protokoldür.
appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*",
"EmailSettings": {
"Host": "smtp.domain.com",
"Port": 465,
"Name": "NOREPLY",
"Email": "noreply@domain.com",
"UserName": "noreply@domain.com",
"Password": "password",
"UseSsl": true
}
}
EmailSetting sectionına gerekli SMTP Bilgilerimizi giriyoruz.
EmailSettings.cs
public class EmailSettings
{
public string Host { get; set; }
public int Port { get; set; }
public bool UseSsl { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
}
appsettings.json içerisindeki bilgileri alabilmek için EmailSettings.cs diye bir class oluşturuyoruz.
IEmailService.cs ve IViewRenderService.cs interfacelerini oluşturuyoruz.
public interface IEmailService
{
string GetPartialViewHtml(string partialViewName, object model);
void SendEmail(string email, string subject, string body);
}
public interface IViewRenderService
{
Task<string> RenderToStringAsync(string viewName, object model);
}
EmailService.cs ve ViewRenderService.cs servislerini oluşturuyoruz. Email'i Açık kaynaklı olan, MailKit package kullanarak gönderiyorum.
public class EmailService : IEmailService
{
private readonly IViewRenderService _viewRenderService;
private readonly EmailSettings _emailSettings;
public EmailService(IViewRenderService viewRenderService, EmailSettings emailSettings)
{
_viewRenderService = viewRenderService;
_emailSettings = emailSettings;
}
public string GetPartialViewHtml(string partialViewName, object model)
{
return _viewRenderService.RenderToStringAsync(partialViewName, model).Result;
}
public void Send(string email, string subject, string body)
{
try
{
var messageToSend = new MimeMessage
{
Subject = subject
};
messageToSend.To.Add(new MailboxAddress(email));
messageToSend.From.Add(new MailboxAddress(_emailSettings.Name, _emailSettings.Email));
messageToSend.Body = new TextPart(TextFormat.Html) { Text = body };
using (var smtp = new MailKit.Net.Smtp.SmtpClient())
{
//smtp.MessageSent += (sender, args) => { };
smtp.ServerCertificateValidationCallback = (s, c, h, e) => true;
smtp.Connect(_emailSettings.Host, _emailSettings.Port, _emailSettings.UseSsl);
smtp.Authenticate(_emailSettings.UserName, _emailSettings.Password);
smtp.Send(messageToSend);
smtp.Disconnect(true);
}
}
catch (Exception ex)
{
}
}
public void SendEmail(string email, string subject, string body)
{
BackgroundJob.Enqueue(() => Send(email, subject, body));
}
}
public class ViewRenderService : IViewRenderService
{
private readonly IRazorViewEngine _razorViewEngine;
private readonly ITempDataProvider _tempDataProvider;
private readonly IServiceProvider _serviceProvider;
public ViewRenderService(IRazorViewEngine razorViewEngine,
ITempDataProvider tempDataProvider,
IServiceProvider serviceProvider)
{
_razorViewEngine = razorViewEngine;
_tempDataProvider = tempDataProvider;
_serviceProvider = serviceProvider;
}
public async Task<string> RenderToStringAsync(string viewName, object model)
{
var httpContext = new DefaultHttpContext { RequestServices = _serviceProvider };
var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
using (var sw = new StringWriter())
{
var viewResult = _razorViewEngine.FindView(actionContext, viewName, false);
if (viewResult.View == null)
{
throw new ArgumentNullException($"{viewName} does not match any available view");
}
var viewDictionary = new ViewDataDictionary(new EmptyModelMetadataProvider(), new ModelStateDictionary())
{
Model = model
};
var viewContext = new ViewContext(
actionContext,
viewResult.View,
viewDictionary,
new TempDataDictionary(actionContext.HttpContext, _tempDataProvider),
sw,
new HtmlHelperOptions()
);
await viewResult.View.RenderAsync(viewContext);
return sw.ToString();
}
}
}
SendEmailBindingModel.cs ve ThankYouEmailTemplateViewModel.cs binding model ve view modellerimizi oluşturuyoruz.
public class SendEmailBindingModel
{
[Required]
[DataType(DataType.EmailAddress)]
[EmailAddress]
public string Email { get; set; }
}
public class ThankYouEmailTemplateViewModel
{
public ThankYouEmailTemplateViewModel(string fullName, string description)
{
FullName = fullName;
Description = description;
}
public string FullName { get; set; }
public string Description { get; set; }
}
Index.cshtml.cs dosyasında Handler (Action) methodumuzu oluşturuyoruz.
[BindProperty]
public SendEmailBindingModel SendEmailBindingModel { get; set; }
public void OnPostSendEmail()
{
var thankYouEmailTemplateHtml = _emailService.GetPartialViewHtml("../EmailTemplates/ThankYouEmailTemplate", new ThankYouEmailTemplateViewModel("Ayaz Duru", "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas eu ullamcorper tellus. Nulla eu lacinia metus. Duis tempor dictum tortor a ultricies. Donec interdum neque quis lacus porta, a varius dui iaculis."));
_emailService.SendEmail(SendEmailBindingModel.Email,"Thank You" , thankYouEmailTemplateHtml);
}
Ben projeyi Razor Pages olarak açtım. Siz dilerseniz projeyi MVC olarak açıp gerekli değişiklikleri ona göre yaparsınız.
Son olarak Startup.cs içerisinde düzenlemeler yapıyoruz.
public void ConfigureServices(IServiceCollection services)
{
.....
services.AddScoped<IViewRenderService, ViewRenderService>();
var emailSettings = Configuration.GetSection(nameof(EmailSettings)).Get<EmailSettings>();
services.AddSingleton(emailSettings);
services.AddTransient<IEmailService, EmailService>();
services.AddHangfire(config =>
{
config.UseMemoryStorage();
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
.....
app.UseHangfireServer();
}
EmailService içerisinde Hangfire kullanmamın sebebi;
Email'i SMTP ile gönderirken handler'ın beklemesini yani kullanıcının beklemesini önlemek. Bu sayede Hangfire ile Email arka planda gönderiliyor.
ThankYouEmailTemplate.cshtml dosyasına mailde gönderilecek email template html'i ekliyoruz.
SONUÇ:

BONUS
https://beefree.io/templates/ sitesinde hazır HTML Email Template'leri bulabilir, düzenleyebilir veya yeni bir tane oluşturabilirsiniz.
Tekrar başka bir yazımda görüşmek dileğiyle :)