Skip to content

Introduction to sending Email correctly


Note: This was adapted from this YouTube video.


System.Net,Mail has been around since .NET 2.0, but is getting a bit out of date now. In the official .NET documentation it even says the following:

The SmtpClient type is not recommended for new development

and

We don't recommend that you use the SmtpClient class for new development because SmtpClient doesn't support many modern protocols. Use MailKit or other libraries instead.

MailKit itself is built on top of MimeKit. So skipping over the details:

  • MimeKit: Is the library we use to build Email messages.
  • MailKit: Is the library we use to use to send those messages.

We can add the MailKit package to our project via NuGet package manager, or via the command line:

dotnet add package MailKit

MailKit will install MimeKit as one of its dependencies.

Now we are ready to create a message:

var message = new MimeMessage();

To specify the sender we create a new MailboxAddress and add this to the from collection on our MimeMessage:

var from = new MailboxAddress("Stuart", "stu@imorital.net");
message.From.Add(from);

We do a similar thing for the recipient, but add this to the message's To collection:

var to = new MailboxAddress("Bob", "bob@imorital.net");
message.To.Add(to);

The message subject is just a string:

message.Subject = "Test email from MimeKit";

Now we define the body as a TextPart object, and specify the message format as plain text (in this example):

message.Body = new TextPart(MimeKit.Text.TextFormat.Plain)
{
    Text = """
    This is a test email sent from MimeKit.

    The body here should just be in plain text.

    Let's hope it works!
    """
};

Note: This is using a raw string literal which is a string surrounded in triple quotes and allows multi line strings. By indenting the closing triple quotes, the compiler will strip the leading whitespace from each line of the string automatically.


Now we can send the email:

using var smtp = new SmtpClient();
await smtp.ConnectAsync("localhost", 1025);
await smtp.SendAsync(message);
await smtp.DisconnectAsync(true);

Note: Ensure you import the SmtpClient from the MailKit.Net.Smtp namespace rather than the System.Net.Mail namespace.


Note: By specifying true as the parameter in await smtp.DisconnectAsync(true); we send a quit command to the SMTP server to close the server connection properly, rather than just closing the connection locally.


Note: For this code to run we need an SMTP server running on localhost port 1025. (Instructions for how to do this are in the source readme, as it's not really part of this overview)


To send emails with an attachment we must create a multi-part email like this using the BodyBuilder class:

message = new MimeMessage();
message.From.Add(from);
message.To.Add(to);
message.Subject = "Test email with attachment from MimeKit";
var bodybuilder = new BodyBuilder();
bodybuilder.TextBody = "The body here should just be in plain text.";
bodybuilder.HtmlBody = "<p>The body here should be in <b>HTML</b>.</p>";
bodybuilder.Attachments.Add("attachment.txt");
message.Body = bodybuilder.ToMessageBody();

using var secondSmtp = new SmtpClient();
await secondSmtp.ConnectAsync("localhost", 1025);
await secondSmtp.SendAsync(message);
await secondSmtp.DisconnectAsync(true);

The attachment could be anything, not just a txt file but also a jpg, pdf, whatever. The Raw data will set up boundaries to separate parts of the message.

Displaying images inline

To display an image (for example) inline with the HTML message body, do the following:

message = new MimeMessage();
message.From.Add(from);
message.To.Add(to);
message.Subject = "Test email with embedded image from MimeKit";
var builder = new BodyBuilder();
var image = builder.LinkedResources.Add("image.png");
image.ContentId = MimeUtils.GenerateMessageId();
builder.HtmlBody = string.Format("<p>This email contains an embedded image.</p><img src=\"cid:{0}\" alt=\"Image alt text\">", image.ContentId);
message.Body = builder.ToMessageBody();

using var thirdSmtp = new SmtpClient();
await thirdSmtp.ConnectAsync("localhost", 1025);
await thirdSmtp.SendAsync(message);
await thirdSmtp.DisconnectAsync(true);

Note: This will need to add a reference to MimeKit.Utils


Source Code

I have implemented this example on one of my Git repos in GitHub here.