Real-time email verification in .NET using HttpClient
and System.Text.Json — no external packages needed.
Send a GET request with the email and your API token.
The helper below also handles interim Unknown results by waiting
RetryAfterSeconds and retrying automatically.
using System.Net.Http.Json;
const string ApiUrl = "https://api.validemail.net/";
const string ApiKey = "YOUR_API_KEY"; // find it in your ValidEmail dashboard
using var client = new HttpClient { Timeout = TimeSpan.FromSeconds(90) };
var result = await VerifyEmailAsync("someone@example.com");
Console.WriteLine($"Valid: {result.IsValid}");
Console.WriteLine($"Score: {result.Score}");
Console.WriteLine($"State: {result.State}");
Console.WriteLine($"Reason: {result.Reason}");
if (result.IsValid && result.Score >= 80)
{
Console.WriteLine("Safe to send.");
}
async Task<VerificationResult> VerifyEmailAsync(string email, int maxRetries = 3)
{
VerificationResult? result = null;
for (var attempt = 0; attempt < maxRetries; attempt++)
{
var url = $"{ApiUrl}?email={Uri.EscapeDataString(email)}&token={ApiKey}";
result = await client.GetFromJsonAsync<VerificationResult>(url)
?? throw new InvalidOperationException("Empty response.");
// "Unknown" means the verification is still in progress (e.g. greylisting).
if (result.State == "Unknown" && result.RetryAfterSeconds is int retryAfter)
{
await Task.Delay(TimeSpan.FromSeconds(retryAfter));
continue;
}
return result;
}
return result!; // still pending after maxRetries — treat as risky
}
public sealed record VerificationResult(
bool IsValid,
int Score,
string Email,
string State,
string Reason,
string Domain,
bool Free,
bool Role,
bool Disposable,
bool AcceptAll,
bool Tag,
string MXRecord,
int? RetryAfterSeconds,
List<AdditionalInfo> EmailAdditionalInfo);
public sealed record AdditionalInfo(string Key, string Value);
State = "Unknown")
Some mail servers greylist first-time senders or respond slowly. Instead of failing, the API returns an
interim 200 OK result with State = "Unknown", a Reason of
PENDING or GREYLISTED, and a RetryAfterSeconds hint while the
verification finishes in the background.
RetryAfterSeconds seconds, then repeat the same request to get the final verdict.Unknown as "not yet decided" — never as a delivery failure.The balance endpoint is free to call and never consumes a credit — perfect for a pre-flight check before verifying a large list.
var balanceResponse = await client.GetFromJsonAsync<BalanceResponse>(
$"https://api.validemail.net/balance?token={ApiKey}");
Console.WriteLine($"Credits remaining: {balanceResponse!.Balance}");
public sealed record BalanceResponse(int Balance);
| HTTP Status | Meaning | What to do |
|---|---|---|
| 200 OK | The request was processed. Check State — a result with State = "Unknown" and a RetryAfterSeconds value is an interim answer, not a final verdict. |
Use the result. If State is Unknown, retry the same request after RetryAfterSeconds. |
| 400 Bad Request | Missing email/token parameter, no credits remaining, or a transient processing failure. |
Check the response text. If you are out of credits, top up your balance before retrying. |
| 401 Unauthorized | The API key is invalid or unknown. | Verify the token value against the API key shown in your dashboard. |
| 403 Forbidden | The account attached to this API key is inactive. | Contact info@validemail.net to reactivate the account. |
| 429 Too Many Requests | You exceeded your per-second request limit. The response body includes the configured limit. | Slow down and retry with backoff, or contact us to raise your rate limit. |
Explore every response field and status code in the full API reference.