Verifica delle email in .NET
Questo tutorial integra Mailbeam in un'applicazione ASP.NET Core con modelli idiomatici di .NET: un HttpClient tipizzato, il modello delle opzioni per la configurazione, l'iniezione delle dipendenze e un attributo di validazione riutilizzabile. Funziona allo stesso modo nelle minimal API e nei controller MVC.
Che cosa costruirai
- Un servizio
IEmailVerifiersostenuto da unHttpClienttipizzato - Un attributo di validazione
[VerifiedEmail]per il binding dei modelli - Un endpoint di registrazione con minimal API che rifiuta gli indirizzi non recapitabili
Prerequisiti
- SDK di .NET 8 o successivo
- Una chiave API di Mailbeam (iscriviti gratis)
- Conoscenze di base sull'iniezione delle dipendenze in ASP.NET Core
Passo 1 — Configura la chiave
Conserva la chiave nei segreti utente in locale e in variabili d'ambiente o Key Vault in produzione:
dotnet user-secrets init
dotnet user-secrets set "Mailbeam:ApiKey" "mb_live_xxxxxxxxxxxxxxxxxxxx"Collegala con il modello delle opzioni:
// Options/MailbeamOptions.cs
public sealed class MailbeamOptions
{
public string ApiKey { get; set; } = "";
public int MinScore { get; set; } = 60;
}Passo 2 — Registra un HttpClient tipizzato
// Program.cs
builder.Services.Configure<MailbeamOptions>(
builder.Configuration.GetSection("Mailbeam"));
builder.Services.AddHttpClient<IEmailVerifier, MailbeamVerifier>((sp, client) =>
{
var opts = sp.GetRequiredService<IOptions<MailbeamOptions>>().Value;
client.BaseAddress = new Uri("https://api.mailbeam.dev/");
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", opts.ApiKey);
client.Timeout = TimeSpan.FromSeconds(5);
});Passo 3 — Costruisci il servizio di verifica
// Services/IEmailVerifier.cs
public interface IEmailVerifier
{
Task<bool> IsAcceptableAsync(string email, CancellationToken ct = default);
}
// Services/MailbeamVerifier.cs
public sealed class MailbeamVerifier : IEmailVerifier
{
private readonly HttpClient _http;
private readonly MailbeamOptions _opts;
private readonly ILogger<MailbeamVerifier> _log;
public MailbeamVerifier(
HttpClient http,
IOptions<MailbeamOptions> opts,
ILogger<MailbeamVerifier> log)
{
_http = http;
_opts = opts.Value;
_log = log;
}
private sealed record VerifyResponse(bool Valid, int Score, string? Reason);
public async Task<bool> IsAcceptableAsync(string email, CancellationToken ct = default)
{
try
{
var resp = await _http.PostAsJsonAsync(
"v1/verify", new { email = email.Trim().ToLowerInvariant() }, ct);
resp.EnsureSuccessStatusCode();
var result = await resp.Content.ReadFromJsonAsync<VerifyResponse>(ct);
return result is not null
&& result.Valid
&& result.Score >= _opts.MinScore;
}
catch (Exception ex)
{
// Lascia passare: un guasto dell'API non deve bloccare le registrazioni
_log.LogError(ex, "Verifica di Mailbeam fallita per {Email}", email);
return true;
}
}
}Passo 4 — Aggiungi un attributo di validazione
In MVC e nel binding dei modelli, un attributo tuo tiene la validazione dichiarativa:
// Validation/VerifiedEmailAttribute.cs
public sealed class VerifiedEmailAttribute : ValidationAttribute
{
protected override ValidationResult? IsValid(
object? value, ValidationContext context)
{
if (value is not string email || string.IsNullOrWhiteSpace(email))
return ValidationResult.Success; // lascia i vuoti a [Required]
var verifier = context.GetRequiredService<IEmailVerifier>();
// Gli attributi sono sincroni; blocca brevemente sulla chiamata asincrona
var ok = verifier.IsAcceptableAsync(email).GetAwaiter().GetResult();
return ok
? ValidationResult.Success
: new ValidationResult("Inserisci un indirizzo email valido e recapitabile.");
}
}Passo 5 — Verifica in un endpoint di minimal API
// Program.cs
app.MapPost("/api/signup", async (
SignupRequest req,
IEmailVerifier verifier,
CancellationToken ct) =>
{
if (!await verifier.IsAcceptableAsync(req.Email, ct))
return Results.ValidationProblem(new Dictionary<string, string[]>
{
["email"] = ["Inserisci un indirizzo email valido e recapitabile."]
});
var user = await CreateUserAsync(req.Email, req.Password, ct);
return Results.Created($"/users/{user.Id}", user);
});
public record SignupRequest(string Email, string Password);Passo 6 — Aggiungi la cache
Usa IMemoryCache (o una cache distribuita) per evitare interrogazioni ripetute:
public async Task<bool> IsAcceptableAsync(string email, CancellationToken ct = default)
{
var key = $"mb:{email.Trim().ToLowerInvariant()}";
if (_cache.TryGetValue<bool>(key, out var cached))
return cached;
// ... esegui la chiamata di verifica come nel passo 3 ...
var ok = result is not null && result.Valid && result.Score >= _opts.MinScore;
_cache.Set(key, ok, TimeSpan.FromHours(24));
return ok;
}Prove
Simula il client tipizzato oppure punta i test ai domini di prova di Mailbeam, che sono deterministici e non consumano quota:
[Fact]
public async Task Disposable_Email_Is_Rejected()
{
var verifier = CreateVerifier(); // collegato alla configurazione di test
var ok = await verifier.IsAcceptableAsync("temp@disposable.mailbeam-test.dev");
Assert.False(ok);
}
[Fact]
public async Task Valid_Email_Is_Accepted()
{
var verifier = CreateVerifier();
var ok = await verifier.IsAcceptableAsync("user@valid.mailbeam-test.dev");
Assert.True(ok);
}Buone pratiche
| Pratica | Perché |
|---|---|
HttpClient tipizzato con AddHttpClient | Pool di connessioni, resilienza e simulazione facile |
| Modello delle opzioni per la chiave | Configurazione pulita, senza stringhe magiche |
| Lasciar passare davanti alle eccezioni | Un guasto dell'API non rompe le registrazioni |
Impostare un Timeout di 5 s | Non lasciare la richiesta appesa a un sondaggio lento |
Mettere in cache con IMemoryCache | Riduce le chiamate doppie nei ritentativi |
Lista di controllo per la produzione
- Chiave API nei segreti utente o in Key Vault, mai nel codice
- Tempo di attesa massimo dell'
HttpClientconfigurato - Registrazione degli errori sui fallimenti di verifica
- Cache distribuita nelle pubblicazioni con più istanze
- Domini di prova usati nei test unitari