Email Verification API - .NET / C# 2026 | BounceZero
Blog›Developer Guides

Email Verification API
.NET / C# 2026

Production-ready .NET integration examples for the BounceZero email verification API: IHttpClientFactory, ASP.NET Core minimal API middleware, background IHostedService for queue processing, and Polly retry policies for resilient verification pipelines.

By BounceZero Team |July 2026 |7 min read

API response fields

Field C# type Description
classification string "valid" | "invalid" (binary verdict)
score int 0-100 confidence score
is_deliverable bool true when the address is safe to send to
risk_level string "low" | "medium" | "high" (catch-all valids are medium)
checks.not_disposable bool? false for known throwaway email services
metadata.internal_classification string detail: verified, likely_valid, catch_all, invalid, risky, unknown, disposable, spamtrap, error
metadata.refunded bool? true = could not be verified, credit auto-refunded

1. Register the service - Program.cs

Always use IHttpClientFactory - avoids socket exhaustion from direct HttpClient instantiation.

// Program.cs
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddHttpClient<BounceZeroService>(client =>
{
    client.BaseAddress = new Uri("https://api.bouncezero.io/");
    client.DefaultRequestHeaders.Add(
        "X-API-Key",
        builder.Configuration["BounceZero:ApiKey"]
    );
    // HttpClient sends no User-Agent by default; requests without one are rejected (403)
    client.DefaultRequestHeaders.UserAgent.ParseAdd("my-app/1.0");
    client.Timeout = TimeSpan.FromSeconds(10);
});

// appsettings.json
// "BounceZero": { "ApiKey": "YOUR_API_KEY" }

2. Service class with typed client

// BounceZeroService.cs
using System.Net.Http.Json;
using System.Text.Json.Serialization;

public record VerifyMetadata(
    [property: JsonPropertyName("internal_classification")] string? InternalClassification, // verified, catch_all, disposable, unknown, ...
    [property: JsonPropertyName("refunded")] bool? Refunded,                                 // true = could not verify, credit refunded
    [property: JsonPropertyName("catch_all_unresolved")] bool? CatchAllUnresolved
);

public record VerifyResult(
    [property: JsonPropertyName("email")] string Email,
    [property: JsonPropertyName("classification")] string Classification, // "valid" | "invalid"
    [property: JsonPropertyName("score")] int Score,                      // 0-100
    [property: JsonPropertyName("is_deliverable")] bool IsDeliverable,
    [property: JsonPropertyName("risk_level")] string RiskLevel,          // "low" | "medium" | "high"
    [property: JsonPropertyName("metadata")] VerifyMetadata? Metadata
);

public class BounceZeroService(HttpClient http)
{
    public async Task<VerifyResult?> VerifyAsync(
        string email,
        CancellationToken ct = default)
    {
        using var res = await http.PostAsJsonAsync("api/v1/verify", new { email }, ct);
        res.EnsureSuccessStatusCode();
        return await res.Content.ReadFromJsonAsync<VerifyResult>(cancellationToken: ct);
    }

    // Accept valid; also let through "could not verify" (refunded) rather than block a real user
    public bool IsAcceptable(VerifyResult result) =>
        result.Classification == "valid" ||
        result.Metadata?.Refunded == true;
}

3. ASP.NET Core minimal API - signup endpoint

Fail-open: if the verification service is unavailable, the request proceeds.

// Program.cs (continued)
app.MapPost("/api/signup", async (
    SignupRequest req,
    BounceZeroService bz,
    CancellationToken ct) =>
{
    try
    {
        var verification = await bz.VerifyAsync(req.Email, ct);

        if (verification is not null && !bz.IsAcceptable(verification))
        {
            return Results.UnprocessableEntity(new
            {
                error = "invalid_email",
                message = "Please use a valid work email address."
            });
        }
    }
    catch (Exception)
    {
        // fail-open: API unavailable > allow the signup
    }

    // proceed with account creation...
    return Results.Ok(new { status = "created" });
});

record SignupRequest(string Email, string Name);

4. Background IHostedService - async bulk queue

For user import flows: enqueue addresses, verify in background, mark unverified accounts for email confirmation.

// EmailVerificationWorker.cs
public class EmailVerificationWorker(
    IServiceScopeFactory scopeFactory,
    Channel<string> queue) : BackgroundService
{
    protected override async Task ExecuteAsync(CancellationToken ct)
    {
        await foreach (var email in queue.Reader.ReadAllAsync(ct))
        {
            await using var scope  = scopeFactory.CreateAsyncScope();
            var bz  = scope.ServiceProvider.GetRequiredService<BounceZeroService>();
            var db  = scope.ServiceProvider.GetRequiredService<AppDbContext>();

            try
            {
                var result = await bz.VerifyAsync(email, ct);
                var user   = await db.Users.FirstAsync(u => u.Email == email, ct);

                user.EmailVerified  = result?.Classification == "valid";
                user.IsDisposable   = result?.Metadata?.InternalClassification == "disposable";
                user.VerifiedAt     = DateTimeOffset.UtcNow;
                await db.SaveChangesAsync(ct);
            }
            catch (Exception ex)
            {
                // log and move on - don't block the queue
            }
        }
    }
}

// Register in Program.cs:
// builder.Services.AddSingleton(Channel.CreateBounded<string>(1000));
// builder.Services.AddHostedService<EmailVerificationWorker>();

New to verification? Start with the complete email verification guide.

Frequently Asked Questions

How do I verify an email address in C#?

Use IHttpClientFactory to call the BounceZero REST API. Set the X-API-Key header, POST {"email": "..."} to /api/v1/verify, and deserialise the JSON response into a record. Check Classification (valid or invalid) and Metadata.InternalClassification before allowing the address through.

Should I use HttpClient directly or IHttpClientFactory in .NET?

Always use IHttpClientFactory. Direct HttpClient instantiation causes socket exhaustion under load because TCP connections are not released immediately on dispose. IHttpClientFactory manages a shared pool of HttpMessageHandler instances safely across the application lifetime.

Get your .NET integration live in minutes.

Sign up for a BounceZero account, get your API key, and paste the typed client above. 100 free verifications - no credit card required.

Build with the BounceZero API

Endpoints, code samples, and language guides