When you build a website, there is a big chance that you need email functionality at some point. There are many email packages available for you for this task. Dot Net Core encourages you to configure your email, or other packages using the Dependency Injection principle. This blog shows you how.
Why Dependency Injection?
DI (Dependency Injection) helps you to create loosely coupled application modules. A class receives in the constructor a interface reference to the service object, rather then creating new instance to the service object. This is know as the Explicit Dependencies Principle or "constructor injection". The class has no knowledge about the service object, it just knows how to use it. This makes testing and migrating to an other service component much easier. Dot Net Core fully embrace the Dependency Injection patern. The service is registered during startup. After registration is the service available as a parameter in the controller class constructor. I explain this later in more detail.
Demo Application
With several steps I create a sample application, where we can see how it all works. We build the application in serveral steps.
- Create demo MVC application.
- Add email package.
- Configure email settings.
- Create email service interface and class.
- Register email service in startup.
- Inject email service in controller.
Create demo MVC application
Start Visual Studio and create a new MVC Core application. Authentication is not needed for this demo
Add mail package
I use the MailKit library for this demo. It works well and has an elegant API. Install the mail package from nuget:
pm> Install-Package NETCore.MailKit
Configure email settings in appsettings.json
It's good pratice to configure settings outside the application using a config file. In .Net Core settings are moved to the appsettings.json file. Adding the mail settings is the first step.
...
"Email": {
"FromName": "<fromname>",
"FromAddress": "<fromaddress>",
"LocalDomain": "<localdomain>",
"MailServerAddress": "<mailserveraddress>",
"MailServerPort": "<mailserverport>",
"UserId": "<userid>",
"UserPassword": "<userpasword>"
},
...
You can read the settings with a customized class.
public class EmailConfig
{
public String FromName { get; set; }
public String FromAddress { get; set; }
public String LocalDomain { get; set; }
public String MailServerAddress { get; set; }
public String MailServerPort { get; set; }
public String UserId { get; set; }
public String UserPassword { get; set; }
}
The EmailConfig class is used for reading the settings during startup. The section parameter specifies where to read within the appsettings.json file.
public void ConfigureServices(IServiceCollection services)
{
...
services.Configure<EmailConfig>(Configuration.GetSection("Email"));
...
}
Create email service interface and class
.Net Core DI requires two items:
- Interface.
- Implementing class.
The interface defines the available functionality. The implementing class, as the name implies implements the interface functionality.
public interface IEmailService
{
Task SendEmailAsync(string email, string subject, string message);
}
public class EmailService : IEmailService
{
private readonly EmailConfig ec;
public EmailService(IOptions<EmailConfig> emailConfig)
{
this.ec = emailConfig.Value;
}
public async Task SendEmailAsync(String email, String subject, String message)
{
try
{
var emailMessage = new MimeMessage();
emailMessage.From.Add(new MailboxAddress(ec.FromName, ec.FromAddress));
emailMessage.To.Add(new MailboxAddress("", email));
emailMessage.Subject = subject;
emailMessage.Body = new TextPart(TextFormat.Html) { Text = message };
using (var client = new SmtpClient())
{
client.LocalDomain = ec.LocalDomain;
await client.ConnectAsync(ec.MailServerAddress, Convert.ToInt32(ec.MailServerPort), SecureSocketOptions.Auto).ConfigureAwait(false);
await client.AuthenticateAsync(new NetworkCredential(ec.UserId, ec.UserPassword));
await client.SendAsync(emailMessage).ConfigureAwait(false);
await client.DisconnectAsync(true).ConfigureAwait(false);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
The constructor parameter IOptions<EmailConfig> emailConfig provides easy access to the emailsettings without knowing where or how the settings are configured. The MailKit package is used to implement the actual mailing. Supose you want to switch to an other mail service, you only need to change this implementation class. This perfectly fits the Single Responsibility principle.
Register email service in startup.
The next step is to register the interface and the implementation class during startup.
public void ConfigureServices(IServiceCollection services)
{
...
services.AddTransient<IEmailService, EmailService>();
...
}
Every time a IEmailService reference is requested, a EmailService instance delivered.
Inject email service in controller
After all this works comes the fun part. It's now very easy to make the emailservice available to a controler. Just add a IEmailService parameter in the controller constructor and the MVC framework takes care of the dependency injection!
public class HomeController : Controller
{
private readonly IEmailService _emailService;
public HomeController(IEmailService emailService)
{
_emailService = emailService;
}
Set a breakpoint, start the application and the debugger shows it's all working as expected:
The last step is to actually use the email service for sending a mail. I made simple input form and an action handler on the controller to demonstrate this.
[HttpPost()]
public async Task<IActionResult> Index(MailViewModel model)
{
if (ModelState.IsValid)
{
await _emailService.SendEmailAsync(model.MailTo, model.Subject, model.Message);
ViewBag.Succes = true;
}
return View(model);
}
I added the source code so you can play with it. The source code is base on .Net Core 1.10. You can download de SDK here.
Conclusion
You can send mail from a .Net Core application, configured with the DI (Dependency Injection) principle. Dot Net Core supports DI out of the box, there is no need for third party tooling. The DI configuration takes some effort. In return you get all the benefits such as loosely coupling, Single Point of Resposibility and better testing possibilities.
Further reading
MailKit New is glue
wiki deendency injection
Dot Net Core dependency injection