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 |
Recommended libraries for C# email
Use:
MailKitfor robust SMTP and MIME handling.MailSlurpNuGet 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.