Sending An Email In C#/.NET

How do you send an email in C#/.NET? That sounds like it should be simple, after all, electronic mail existed decades before the Internet.

If you've worked with emails for any length of time, you'll soon hear about the Simple Mail Transfer Protocol (SMTP) for sending and Internet Message Access Protocol (IMAP - which replaced POP3) for receiving. That's an important distinction to take note of: sending, and receiving emails use different protocols.

System.Net.Mail

At first glance, SMTP seems relatively straightforward.

Here's how to write an email using System.Net.Mail (there's a better way though):

var smtpClient = new SmtpClient("smtp.example.com"){
    Port = 587,
    Credentials = new NetworkCredential("username", "password"),
    EnableSsl = true,
};
smtpClient.Send("from@example.com", "to@example.com", "subject", "body");

That doesn't actually look that bad, and might be all you need at the moment.

You can even re-write it to make an email object called MailMessage first:

var mailMessage = new MailMessage{
    From = new MailAddress("from@example.com"),
    To = new MailAddress("to@example.com"),
    Subject = "subject",
    Body = "<p>Hello</p>",
    IsBodyHtml = true,
};
smtpClient.Send(mailMessage);

 You can also move the client definition to a separate appsettings.json file like so:

{
  "EmailSender": {
    "SmtpHost": "smtp.example.com",
    "SmtpPort": 587,
    "SmtpCredential": {
      "UserName": "username",
      "Password": "password"
    }
  }
}

You could read those settings with Microsoft.Extensions.Configuration.Json and use them as follows (keep reading though, there's a better way!): 

using Microsoft.Extensions.Configuration;
var configuration = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build();
var smtpClient = new SmtpClient(configuration["EmailSender:SmtpHost"]){
    Port = int.Parse(configuration["EmailSender:SmtpPort"]),
    Credentials = new NetworkCredential(configuration["EmailSender:SmtpCredential:UserName"], configuration["EmailSender:SmtpCredential:Password"]),
    EnableSsl = true,
};

Let's simplify that by parsing the configuration to a predefined object type (later we'll re-use MailKitSimplified.Sender.Models.EmailSenderOptions):

using Microsoft.Extensions.Configuration;
var configuration = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build();
var emailSenderOptions = configuration.GetRequiredSection(EmailSenderOptions.SectionName).Get<EmailSenderOptions>();
var smtpClient = new SmtpClient(emailSenderOptions.SmtpHost){
    Port = emailSenderOptions.SmtpPort,
    Credentials = emailSenderOptions.SmtpCredential,
    EnableSsl = emailSenderOptions.SmtpPort == 587 ? true : false,
};

Unfortunately for us, System.Net.Mail doesn't fully implement Multipurpose Internet Mail Extensions (MIME) types defined in the RFC standards. That's all the Internet is reallly, connections based on global standards, so they should be adhered to. Is there a package that does?

MailKit and MimeKit

If you read about it online, you'll quickly discover that even Microsoft recommends using MailKit.

Here's how to write an email using MailKit and the MimeKit dependency:

var mailMessage = new MimeMessage();
mailMessage.From.Add(new MailboxAddress("from name", "from@example.com"));
mailMessage.To.Add(new MailboxAddress("to name", "to@example.com"));
mailMessage.Subject = "subject";
mailMessage.Body = new TextPart(){
    Text = "Hello"
};
using (var smtpClient = new SmtpClient()){
    smtpClient.Connect("smtp.example.com", 587, true);
    smtpClient.Authenticate("username", "password");
    smtpClient.Send(mailMessage);
    smtpClient.Disconnect(true);
}

Wait a minute, is it just me or did we just make sending an email harder than it was with System.Net.Mail? That's unfortunately the downside of being an all-in-one .NET solution for email. MailKit can have a bit of a learning curve to set up and use. Is there a better way?

There is.

MailKitSimplified.Sender

By adding the MailKitSimplified.Sender package from NuGet, you can still do everything MailKit does as that's still used under the hood, but all of the pain points go away:

using var smtpSender = SmtpSender.Create("smtp.example.com", 587, "username", "password");
smtpSender.WriteEmail
    .From("my.name@example.com")
    .To("YourName@example.com")
    .Subject("Hello World")
    .BodyHtml("<p>Hi</p>")
    .Send();

What about defining the sender options in an application configuration file? We could do that manually with MailKitSimplified.Sender.Models.EmailSenderOptions like we did before:

using var smtpSender = SmtpSender.Create(emailSenderOptions);

If you know how dependency injection works then it's even easier using MailKitSimplified.Sender:

services.AddMailKitSimplifiedEmailSender(context.Configuration);

You can even store the written email to copy and re-use:

var email = smtpSender.WriteEmail
    .From("from@example.com")
    .Bcc("admin@example.com")
    .Subject("Hello World")
    .BodyText("Hi")
    .BodyHtml("<p>Hi</p>")
    .TryAttach("CompanyLogo.png");

If you put all that together, you can customise and send emails over and over as simply as:

foreach(var recipient in recipients)
    await email.Copy().To(recipient).Subject($"Hi {recipient}!").SendAsync();

Next Steps

To see more examples and request new features, head over to https://github.com/danzuep/MailKitSimplified.

Look out for my next article coming soon, Receiving Emails In C#/.NET!