Because the legacy SmtpClient inside .NET Core is now marked as deprecated. It is recommended you follow our guide on integrating your .NET code with the MailKit library in our tutorial bellow!
Creating An Email Service
It’s always good practice that when you add in a new library, that you build an abstraction on top of it. If we take MailKit as an example, what if MailKit is later superceded by a better emailing library? Will we have to change references all over our code to reference this new library? Or maybe MailKit has to make a breaking change between versions, will we then have to go through our code fixing all the now broken changes?
Another added bonus to creating an abstraction is that it allows us to map out how we want our service to look before we worry about implementation details. We can take a very high level view of sending an email for instance without having to worry about exactly how MailKit works. Because there is a lot of code to get through, I won’t do too much explaining at this point, we will just run through it. Let’s go!
First, let’s go ahead and create an EmailAddress class. This will have only two properties that describe an EmailAddress.
public class EmailAddress
{
public string Name { get; set; }
public string Address { get; set; }
}
Now we will need something to describe a simple EmailMessage. There are a tonne of properties on an email, for example attachments, CC, BCC, headers etc but we will break it down to the basics for now. Containing all of this within a class means that we can add extra properties as we need them later on.
public class EmailMessage
{
public EmailMessage()
{
ToAddresses = new List();
FromAddresses = new List();
}
public List<EmailAddress> ToAddresses { get; set; } public List<EmailAddress> FromAddresses { get; set; } public string Subject { get; set; } public string Content { get; set; }
}
Now we need to setup our email configuration. That’s our SMTP servers, ports, credentials etc. For this we will make a simple settings class to hold all of this. Since we are good programmers we will use an interface too!
public interface IEmailConfiguration
{
string SmtpServer { get; }
int SmtpPort { get; }
string SmtpUsername { get; set; }
string SmtpPassword { get; set; }
string PopServer { get; } int PopPort { get; } string PopUsername { get; } string PopPassword { get; }
}
public class EmailConfiguration : IEmailConfiguration
{
public string SmtpServer { get; set; }
public int SmtpPort { get; set; }
public string SmtpUsername { get; set; }
public string SmtpPassword { get; set; }
public string PopServer { get; set; } public int PopPort { get; set; } public string PopUsername { get; set; } public string PopPassword { get; set; }
}
Now we actually need to load this configuration into our app. In your appsettings.json, you need to add a section at the root for email settings. It should look something like this :
{
"EmailConfiguration": {
"SmtpServer": "smtp.myserver.com",
"SmtpPort": 465,
"SmtpUsername": "smtpusername",
"SmtpPassword": "smtppassword",
"PopServer": "popserver", "PopPort": 995, "PopUsername": "popusername", "PopPassword" : "poppassword"
}
….Other settings here…
}
In the ConfigureServices method or your startup.cs, we can now pull out this configuration and load it into our app with a single line.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddSingleton(Configuration.GetSection("EmailConfiguration").Get());
}
This allows us to inject our configuration class anywhere in our app.
The final piece of the puzzle is a simple email service that can be used to send and receive email. Let’s create an interface and an implementation that’s empty for now. The implementation should accept our settings object as a constructor.
public interface IEmailService
{
void Send(EmailMessage emailMessage);
List ReceiveEmail(int maxCount = 10);
}
public class EmailService : IEmailService
{
private readonly IEmailConfiguration _emailConfiguration;
public EmailService(IEmailConfiguration emailConfiguration) { _emailConfiguration = emailConfiguration; } public List<EmailMessage> ReceiveEmail(int maxCount = 10) { throw new NotImplementedException(); } public void Send(EmailMessage emailMessage) { throw new NotImplementedException(); }
}
Head back to our ConfigureServices method of our startup.cs to add in a final line to inject in our EmailService everywhere.
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
services.AddSingleton(Configuration.GetSection("EmailConfiguration").Get());
services.AddTransient();
}
Phew! And we are done. If at this point we decided MailKit isn’t for us, we still have an email service that can swap in and out libraries as it needs to, and our calling application doesn’t need to worry about what’s going on under the hood. That’s the beauty of abstracting a library away!
Getting Started With MailKit
Getting started with MailKit is as easy as installing a Nuget package. Simply run the following from your Package Manager Console :
Install-Package MailKit
And hey presto! You now have access to MailKit in your application
Sending Email via SMTP With MailKit
Let’s head back to our email service class and fill out the “Send” method with the actual code to send an email via MailKit. The code to do this is below :
public void Send(EmailMessage emailMessage)
{
var message = new MimeMessage();
message.To.AddRange(emailMessage.ToAddresses.Select(x => new MailboxAddress(x.Name, x.Address)));
message.From.AddRange(emailMessage.FromAddresses.Select(x => new MailboxAddress(x.Name, x.Address)));
message.Subject = emailMessage.Subject; //We will say we are sending HTML. But there are options for plaintext etc. message.Body = new TextPart(TextFormat.Html) { Text = emailMessage.Content }; //Be careful that the SmtpClient class is the one from Mailkit not the framework! using (var emailClient = new SmtpClient()) { //The last parameter here is to use SSL (Which you should!) emailClient.Connect(_emailConfiguration.SmtpServer, _emailConfiguration.SmtpPort, true); //Remove any OAuth functionality as we won't be using it. emailClient.AuthenticationMechanisms.Remove("XOAUTH2"); emailClient.Authenticate(_emailConfiguration.SmtpUsername, _emailConfiguration.SmtpPassword); emailClient.Send(message); emailClient.Disconnect(true); }
}
The comments should be pretty self explanatory, but let’s quickly run through it.
- You can send clear text or HTML emails depending on the “TextFormat” you use when creating your message body
- MailKit has named it’s Smtp class “SmtpClient” which is the same as the framework class. Be careful if you are using Resharper and the like that when you click “Add Reference” you are adding the correct reference.
- You should choose to use SSL whenever available when connecting to the SMTP Server
Because we built out our EmailService, EmailMessage and EmailConfiguration classes earlier, they are all ready to be used immediately!
Receiving Email via POP With MailKit
And now the code to receive email via POP.
public List ReceiveEmail(int maxCount = 10)
{
using (var emailClient = new Pop3Client())
{
emailClient.Connect(_emailConfiguration.PopServer, _emailConfiguration.PopPort, true);
emailClient.AuthenticationMechanisms.Remove("XOAUTH2"); emailClient.Authenticate(_emailConfiguration.PopUsername, _emailConfiguration.PopPassword); List<EmailMessage> emails = new List<EmailMessage>(); for(int i=0; i < emailClient.Count && i < maxCount; i++) { var message = emailClient.GetMessage(i); var emailMessage = new EmailMessage { Content = !string.IsNullOrEmpty(message.HtmlBody) ? message.HtmlBody : message.TextBody, Subject = message.Subject }; emailMessage.ToAddresses.AddRange(message.To.Select(x => (MailboxAddress)x).Select(x => new EmailAddress { Address = x.Address, Name = x.Name })); emailMessage.FromAddresses.AddRange(message.From.Select(x => (MailboxAddress)x).Select(x => new EmailAddress { Address = x.Address, Name = x.Name })); } return emails; }
}
Again, all rather straight forward.
While we only retrieve a few basic details about the email message, the actual MailKit email object has a tonne of data you can inspect including headers, CC addresses, etc. Extend as you need to!
I Got Exception XYZ
SMTP can sometimes be a bit tricky getting right in terms of SSL, TLS, and ports. Worse yet, the exception messages are often either cryptic, or start pushing you in the completely wrong direction.
Free SMTP Server
It’s worth mentioning that if you are a hobbyist with your own website and want to just send a few emails every now and again under your own domain. A great solution that I use for this very blog is MailGun. It has a great free plan that for most people will be more than enough, but also paid plans for when you really need to start sending a lot of email.
In version 1.0 of the framework and 1.6 of the standard, the SMTP client code in .NET was not yet ported over , that is until the release of .NET Core 2.0.
With things ported over, the interfaces and classes are virtually identical to ones you might have used in the full framework. Consider the following written in .NET Core 2.0.
SmtpClient client = new SmtpClient("mysmtpserver");
client.UseDefaultCredentials = false;
client.Credentials = new NetworkCredential("username", "password");
MailMessage mailMessage = new MailMessage();
mailMessage.From = new MailAddress("whoever@me.com");
mailMessage.To.Add("receiver@me.com");
mailMessage.Body = "body";
mailMessage.Subject = "subject";
client.Send(mailMessage);
For the most part, if you had code that could send email via SMTP in the full framework, it’s likely a matter of a copy and paste job to get it going in .NET Core now!
If you are having issues with this, ensure that you are on .NET Core 2.0 framework. You can check this by editing your csproj file, it should look like the following :
Where TargetFramework is set to 2.0. Anything lower and you will not have access to the SmtpClient class!