MailSlurp logo

guides

C# email tutorial for SMTP sending and inbox testing

Send and receive email in C# with MailKit and MailSlurp. Practical .NET patterns for SMTP setup, inbox waits, attachments, and verification flows.

C# email workflows usually need two capabilities:

  • send reliably through SMTP or API,
  • verify receive behavior in tests.

This guide covers both using MailKit and MailSlurp.

var mail = new MailMessage()
{
    From = new MailAddress(inbox.EmailAddress),
    Subject = "This is a test",
    Body = "This is a test email sent from .NET application.",
};
mail.To.Add(inbox.EmailAddress);
client.Send(mail);

Architecture in one view

Layer Purpose Typical library
Outbound send Deliver transactional messages MailKit SMTP client
Inbound verification Confirm message behavior in tests MailSlurp APIs
Validation/quality Reduce bounce and malformed payloads MailSlurp validation endpoints

Use:

  • MailKit for robust SMTP and MIME handling.
  • MailSlurp NuGet package for disposable inboxes, waits, and verification helpers.

Install packages:

dotnet add package mailslurp
dotnet add package mailkit

Configure MailSlurp in .NET

Imports:

using MailKit.Net.Smtp;
using MailKit.Security;
using MimeKit;
using mailslurp.Api;
using mailslurp.Client;
using mailslurp.Model;

Set your API key and configuration:

var config = new Configuration();
config.ApiKey.Add("x-api-key", YOUR_API_KEY);

Create a disposable inbox for testing:

var inboxController = new InboxControllerApi(config);
var inbox = await inboxController.CreateInboxWithOptionsAsync(new CreateInboxDto
{
    InboxType = CreateInboxDto.InboxTypeEnum.SMTPINBOX,
    Name = "My test inbox",
});
var accessDetails = await inboxController.GetImapSmtpAccessAsync(inbox.Id);

Send email with MailKit

Build a MimeMessage:

var message = new MimeMessage();
message.From.Add(new MailboxAddress(name: inbox.Name, address: inbox.EmailAddress));
message.To.Add(new MailboxAddress(name: inbox.Name, address: inbox.EmailAddress));
message.Subject = "Test Email";
message.Body = new TextPart("plain")
{
    Text = @"Hello World!"
};

Send with configured SMTP client:

using (var client = new SmtpClient())
{
    await client.ConnectAsync(host: accessDetails.SecureSmtpServerHost , port: accessDetails.SecureSmtpServerPort, SecureSocketOptions.StartTls);
    // Remove other authentication mechanisms except for PLAIN
    client.AuthenticationMechanisms.Remove("XOAUTH2");
    client.AuthenticationMechanisms.Remove("CRAM-MD5");
    client.AuthenticationMechanisms.Remove("LOGIN");
    await client.AuthenticateAsync(userName: accessDetails.SecureSmtpUsername, password: accessDetails.SecureSmtpPassword);
    await client.SendAsync(message);
    await client.DisconnectAsync(true);
}

Receive and assert email in tests

Wait for the message using WaitForControllerApi:

var waitForControllerApi = new WaitForControllerApi(config);
var email = await waitForControllerApi.WaitForLatestEmailAsync(inbox.Id, 120000, true);

Fetch by ID when needed:

var emailController = new EmailControllerApi(_configuration);
var fullEmail = emailController.GetEmail(email.Id);
Assert.That(fullEmail.Attachments, Has.Count.EqualTo(1));

Attachment handling

Use BodyBuilder for multipart content and attachments:

var message = new MimeMessage();
message.From.Add(new MailboxAddress("Your Name", "your.email@example.com"));
message.To.Add(new MailboxAddress("Recipient Name", "recipient.email@example.com"));
message.Subject = "This is the subject";

var bodyBuilder = new BodyBuilder();

// Add the body text
bodyBuilder.TextBody = "This is the body of the email.";

// Add an image attachment
// Replace "path/to/your/image.jpg" with the actual file path to the image you want to attach
bodyBuilder.Attachments.Add("path/to/your/image.jpg");

message.Body = bodyBuilder.ToMessageBody();

Then send with the same SMTP client workflow.

Validate addresses before send

To reduce bounce risk, validate addresses before large sends:

var verificationControllerApi = new EmailVerificationControllerApi(config);
var results =await verificationControllerApi.ValidateEmailAddressListAsync(new ValidateEmailAddressListOptions(["contact@mailslurp.dev"]) );

Multiple recipients

var message = new MimeMessage();
message.From.Add(new MailboxAddress("Your Name", "your.email@example.com"));

// Adding multiple recipients to the "To" address
message.To.Add(new MailboxAddress("Recipient One Name", "recipient.one@example.com"));
message.To.Add(new MailboxAddress("Recipient Two Name", "recipient.two@example.com"));
// Add more recipients as needed

Example test pattern: verification emails

Use a browser test (Selenium/Playwright), then assert email delivery:

private static Email _email;

[Test, Order(3)]
public void CanReceiveConfirmationEmail()
{
    //
    var waitForControllerApi = new WaitForControllerApi(_mailslurpConfig);
    _email = waitForControllerApi.WaitForLatestEmail(inboxId: _inbox.Id, timeout: TimeoutMillis, unreadOnly: true);

    // verify the contents
    Assert.IsTrue(_email.Subject.Contains("Please confirm your email address"));
}

Extract a verification code:

private static String _confirmationCode;

[Test, Order(4)]
public void CanExtractConfirmationCode()
{
    // we need to get the confirmation code from the email
    var rx = new Regex(@".*verification code is (\d{6}).*", RegexOptions.Compiled);
    var match = rx.Match(_email.Body);
    _confirmationCode = match.Groups[1].Value;

    Assert.AreEqual(6, _confirmationCode.Length);
}

Production checklist for C# email

  • Configure SMTP TLS and timeout values explicitly.
  • Track send failures by SMTP response class.
  • Keep inboxes isolated per test run in CI.
  • Assert subject/body/token behavior before release.

Next resources