Bêta privéeMailbeam est en bêta privée : l'API publique n'est pas encore ouverte.Rejoindre la liste d'attente

Mailbeam
ASP.NET Core + C#Intermédiaire20 minutesMis à jour en janvier 2025

Vérification d'e-mails en .NET

Ce tutoriel intègre Mailbeam à une application ASP.NET Core avec les motifs idiomatiques de .NET : un HttpClient typé, le motif options pour la configuration, l'injection de dépendances et un attribut de validation réutilisable. Cela fonctionne à l'identique en minimal API et dans les contrôleurs MVC.

Ce que vous allez construire

  • Un service IEmailVerifier appuyé sur un HttpClient typé
  • Un attribut de validation [VerifiedEmail] pour le model binding
  • Un endpoint d'inscription en minimal API qui rejette les adresses non distribuables

Prérequis

  • Le SDK .NET 8 ou plus récent
  • Une clé d'API Mailbeam (inscription gratuite)
  • Quelques bases sur l'injection de dépendances dans ASP.NET Core

Étape 1 — Configurer la clé

Rangez la clé dans les user secrets en local, et dans des variables d'environnement ou Key Vault en production :

dotnet user-secrets init
dotnet user-secrets set "Mailbeam:ApiKey" "mb_live_xxxxxxxxxxxxxxxxxxxx"

Reliez-la avec le motif options :

// Options/MailbeamOptions.cs
public sealed class MailbeamOptions
{
    public string ApiKey { get; set; } = "";
    public int MinScore { get; set; } = 60;
}

Étape 2 — Enregistrer un HttpClient typé

// 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);
});

Étape 3 — Construire le service de vérification

// 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)
        {
            // Échec permissif : une erreur d'API ne doit pas bloquer les inscriptions
            _log.LogError(ex, "Échec de la vérification Mailbeam pour {Email}", email);
            return true;
        }
    }
}

Étape 4 — Ajouter un attribut de validation

Pour MVC et le model binding, un attribut maison garde la validation déclarative :

// 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; // on laisse [Required] gérer le vide

        var verifier = context.GetRequiredService<IEmailVerifier>();
        // Les attributs sont synchrones ; on bloque brièvement sur l'appel asynchrone
        var ok = verifier.IsAcceptableAsync(email).GetAwaiter().GetResult();

        return ok
            ? ValidationResult.Success
            : new ValidationResult("Merci de fournir une adresse e-mail valide et distribuable.");
    }
}

Étape 5 — Vérifier dans un endpoint de 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"] = ["Merci de fournir une adresse e-mail valide et distribuable."]
        });

    var user = await CreateUserAsync(req.Email, req.Password, ct);
    return Results.Created($"/users/{user.Id}", user);
});

public record SignupRequest(string Email, string Password);

Étape 6 — Ajouter un cache

Utilisez IMemoryCache (ou un cache distribué) pour éviter les recherches répétées :

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;

    // … exécute l'appel de vérification comme à l'étape 3 …
    var ok = result is not null && result.Valid && result.Score >= _opts.MinScore;
    _cache.Set(key, ok, TimeSpan.FromHours(24));
    return ok;
}

Tester

Moquez le client typé, ou pointez vos tests vers les domaines de test de Mailbeam, qui sont déterministes et ne consomment pas de quota :

[Fact]
public async Task Disposable_Email_Is_Rejected()
{
    var verifier = CreateVerifier(); // relié à la configuration de 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);
}

Bonnes pratiques

PratiquePourquoi
HttpClient typé via AddHttpClientPooling, résilience, moquage aisé
Motif options pour la cléLiaison de configuration propre, sans chaînes magiques
Échec permissif sur exceptionUne panne d'API ne casse pas les inscriptions
Un Timeout de 5 sÉvite de suspendre la requête sur une sonde lente
Cache avec IMemoryCacheSupprime les appels en double lors des réessais

Liste de contrôle avant la mise en production

  • Clé d'API dans les user secrets ou Key Vault, jamais dans le code source
  • Délai d'expiration configuré sur HttpClient
  • Journalisation des échecs de vérification
  • Cache distribué pour les déploiements multi-instances
  • Domaines de test utilisés dans les tests unitaires

Prochaines étapes