Send email with C# / .NET over SMTP (MailKit)

C# SMTP example with MailKit (the .NET-recommended library) using STARTTLS on 587 or SSL on 465, authentication, HTML body, attachments and async sending; plus the legacy System.Net.Mail.SmtpClient equivalent.

Install

shell
dotnet add package MailKit

Complete example

C# / .NET — STARTTLS on 587, credentials from the environment
using MailKit.Net.Smtp;
using MailKit.Security;
using MimeKit;

var host = Environment.GetEnvironmentVariable("SMTP_HOST") ?? "smtp.queensmtp.com";
var port = int.Parse(Environment.GetEnvironmentVariable("SMTP_PORT") ?? "587");
var user = Environment.GetEnvironmentVariable("SMTP_USER");
var pass = Environment.GetEnvironmentVariable("SMTP_PASS");

var message = new MimeMessage();
message.From.Add(new MailboxAddress("Your App", "hello@yourdomain.com"));
message.To.Add(MailboxAddress.Parse("customer@example.com"));
message.Subject = "Your receipt";
message.Body = new BodyBuilder
{
    TextBody = "Thanks for your order #1042",
    HtmlBody = "<h1>Thanks for your order</h1><p>#1042 is confirmed.</p>",
    // Attachments = { "invoice-1042.pdf" }
}.ToMessageBody();

using var client = new SmtpClient();
client.Timeout = 20000;
await client.ConnectAsync(host, port,
    port == 465 ? SecureSocketOptions.SslOnConnect : SecureSocketOptions.StartTls);
await client.AuthenticateAsync(user, pass);
await client.SendAsync(message);
await client.DisconnectAsync(true);

// legacy System.Net.Mail (obsolete in .NET, still common):
// using var smtp = new System.Net.Mail.SmtpClient(host, 587) { EnableSsl = true,
//     Credentials = new System.Net.NetworkCredential(user, pass) };
// smtp.Send("hello@yourdomain.com", "customer@example.com", "Your receipt", "Thanks");

What to know

  • Microsoft marks System.Net.Mail.SmtpClient as not recommended (no modern auth, no async); MailKit is the supported path.
  • SecureSocketOptions.StartTls for 587/2525, SslOnConnect for 465 — EnableSsl=true on the old client means STARTTLS and does NOT work on 465.
  • Office 365 with basic auth disabled needs OAuth2 (MailKit supports SaslMechanismOAuth2); a relay avoids that entirely.

Same code, different provider

Only the host, port and credentials change. The rules per provider are on the SMTP settings hub.

ProviderHostPortUsernamePasswordNote
QueenSMTP smtp.queensmtp.com587 (STARTTLS) / 465 (SSL) / 2525SMTP username from the dashboardSMTP password$5/year + $0.10 per 1,000; 100 free/day
Gmail smtp.gmail.com587 / 465you@gmail.comApp Password500/day, From must be the account
Amazon SES email-smtp.<region>.amazonaws.com587 / 465 / 2587SES SMTP usernameSES SMTP passwordsandbox 200/day until approved
Office 365 smtp.office365.com587user@yourdomain.commailbox passwordSMTP AUTH must be enabled; 30/min
SendGrid smtp.sendgrid.net587 / 465 / 2525apikeyAPI keyno free plan since 2025

Credentials for the example above

Create a free account, verify your sending domain (SPF + DKIM shown in the dashboard), add an SMTP credential, and paste it into the code. 100 emails a day free; $5/year plus $0.10 per 1,000 after that. Prefer HTTPS? The same account has a REST email API.

Get SMTP credentials Test your settings first

Other languages and frameworks

Examples tested 2026-08-30. If a library changed its API, tell us.

C# / .NET SMTP — questions

Credentials were not sent or basic auth is disabled on the tenant (Office 365). Check EnableSsl/StartTls, the credential object, and SMTP AUTH on the mailbox.