All posts
    Tutorials

    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);
        }
    }
    csharp
    var email = await dm.WaitForEmailAsync(id, "subject=" + Uri.EscapeDataString("reset"));
    var link = email.GetProperty("primaryLink").GetString();

    Tips

    • Keep HttpClient.Timeout above the wait timeout (65s above; the default 100s also covers it).
    • Set DEVMAILR_API_KEY as 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.