All postsTutorials
Email Testing in C# and .NET
The Devmailr Team6 min read
.NET apps send verification and reset emails like any other — and your xUnit (or NUnit) suite can confirm they actually go out by reading them from a disposable inbox. Here’s a small HttpClient-based client and a test.
A small client (HttpClient)
Devmailr.cs
using System.Net.Http.Json;
using System.Text.Json;
public class Devmailr
{
private readonly HttpClient _http = new()
{
BaseAddress = new Uri("https://api.devmailr.app/api/"),
Timeout = TimeSpan.FromSeconds(65), // /wait long-polls
};
public Devmailr()
{
var key = Environment.GetEnvironmentVariable("DEVMAILR_API_KEY");
_http.DefaultRequestHeaders.Authorization = new("Bearer", key);
}
public async Task<JsonElement> CreateInboxAsync(string prefix)
{
var res = await _http.PostAsJsonAsync("mailboxes", new { prefix });
return await res.Content.ReadFromJsonAsync<JsonElement>();
}
public async Task<JsonElement> WaitForEmailAsync(string id, string query = "")
{
var res = await _http.GetAsync($"mailboxes/{id}/wait?timeout=60&{query}");
return await res.Content.ReadFromJsonAsync<JsonElement>();
}
public Task DeleteInboxAsync(string id) => _http.DeleteAsync($"mailboxes/{id}");
}The test (xUnit)
SignupEmailTests.cs
using Xunit;
public class SignupEmailTests
{
[Fact]
public async Task Signup_Sends_Verification_Code()
{
var dm = new Devmailr();
var inbox = await dm.CreateInboxAsync($"net-{DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()}");
var address = inbox.GetProperty("address").GetString();
var id = inbox.GetProperty("_id").GetString()!;
// trigger your app to email a code to 'address'
await SignUpAsync(address);
var email = await dm.WaitForEmailAsync(id, "has_code=true");
var code = email.GetProperty("extractedCodes")[0].GetString();
Assert.Matches(@"^\d{6}$", code);
await dm.DeleteInboxAsync(id);
}
}Magic links and reset links
csharp
var email = await dm.WaitForEmailAsync(id, "subject=" + Uri.EscapeDataString("reset"));
var link = email.GetProperty("primaryLink").GetString();Tips
- Keep
HttpClient.Timeoutabove the wait timeout (65s above; the default 100s also covers it). - Set
DEVMAILR_API_KEYas a CI secret / environment variable. - NUnit works the same — swap
[Fact]for[Test]. - Unique prefix per test (a Unix-ms timestamp) for parallel safety.
Related reading
Try it in two minutes
Create a disposable prefix@devmailr.app inbox over the API, send mail to it from your app, and read it in your tests. Free plan, no card required.