Tutorial
Invia email con .NET
Invia email da ASP.NET Core e .NET con il pacchetto NuGet di Emailit, con MailKit o System.Net.Mail via SMTP, e verifica i webhook di Emailit.
Questa guida mostra come inviare email da un’app .NET con il pacchetto NuGet ufficiale Emailit, come usare in alternativa MailKit o System.Net.Mail via SMTP e come verificare i webhook in una minimal API ASP.NET Core.
Prerequisiti
- .NET 8 o versioni successive.
- Un dominio di invio verificato, ad esempio
acme.com. - Una chiave API. Basta una chiave di solo invio limitata al tuo dominio.
- Finché il workspace non ha l’accesso alla produzione, puoi inviare solo agli indirizzi email degli account dei membri del workspace.
Installa l’SDK
dotnet add package EmailitConfigura la chiave API
ASP.NET Core legge la configurazione dalle variabili d’ambiente, in cui __ separa le sezioni. In produzione imposta Emailit__ApiKey:
export Emailit__ApiKey=secret_••••••••••••••••••••••••••••••••Durante lo sviluppo, tieni la chiave negli user secrets invece che in appsettings.json:
dotnet user-secrets init
dotnet user-secrets set "Emailit:ApiKey" "secret_••••••••••••••••••••••••••••••••"Invia un’email
Registra un unico client e iniettalo negli endpoint:
using Emailit;
using Emailit.Options;
using Emailit.Resources;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSingleton(new EmailitClient(builder.Configuration["Emailit:ApiKey"]!));
var app = builder.Build();
app.MapPost("/orders/{id}/confirm", (string id, EmailitClient emailit) =>
{
Email email = emailit.Emails.Send(new EmailSendOptions
{
From = "Acme <orders@acme.com>",
To = new[] { "ada@example.com" },
Subject = $"Order {id} confirmed",
Html = $"<p>We've received order {id}.</p>",
});
return Results.Ok(new { emailId = email.Id });
});
app.Run();Send è sincrono; per gli invii massivi, eseguilo da un servizio in background così i thread delle richieste restano liberi. Le opzioni accettano anche Cc, Bcc, ReplyTo, Attachments, Template con Variables, ScheduledAt e Tracking; vedi Invia un’email.
Se il tuo codice crea già oggetti System.Net.Mail.MailMessage, l’SDK può inviarli tramite l’API:
using System.Net.Mail;
var message = new MailMessage("orders@acme.com", "ada@example.com", "Order confirmed", "<p>Thanks!</p>")
{
IsBodyHtml = true,
};
Email email = emailit.Emails.Send(message);Gestisci gli errori
using Emailit.Exceptions;
try
{
emailit.Emails.Send(options);
}
catch (RateLimitException)
{
// 429: back off and retry
}
catch (AuthenticationException)
{
// 401: the API key is missing or invalid
}
catch (UnprocessableEntityException ex)
{
// 422: for example, the from domain isn't verified
logger.LogWarning("Emailit rejected the email: {Message}", ex.Message);
}
catch (ApiErrorException ex)
{
logger.LogError("Emailit error {Status}: {Body}", ex.HttpStatus, ex.HttpBody);
}Invia con SMTP
MailKit
Microsoft consiglia MailKit per il nuovo codice SMTP. Installalo con dotnet add package MailKit:
using MailKit.Net.Smtp;
using MailKit.Security;
using MimeKit;
var message = new MimeMessage();
message.From.Add(new MailboxAddress("Acme", "orders@acme.com"));
message.To.Add(MailboxAddress.Parse("ada@example.com"));
message.Subject = "Order confirmed";
message.Body = new TextPart("html") { Text = "<p>We've received your order.</p>" };
using var smtp = new SmtpClient();
await smtp.ConnectAsync("smtp.emailit.com", 587, SecureSocketOptions.StartTls);
await smtp.AuthenticateAsync("emailit", builder.Configuration["Emailit:ApiKey"]);
await smtp.SendAsync(message);
await smtp.DisconnectAsync(true);Per il TLS implicito, collegati alla porta 465 con SecureSocketOptions.SslOnConnect.
System.Net.Mail
Il client integrato va bene per i casi semplici. Supporta solo STARTTLS, quindi usa la porta 587 (oppure 2525 o 2587):
using System.Net;
using System.Net.Mail;
using var client = new SmtpClient("smtp.emailit.com", 587)
{
EnableSsl = true,
Credentials = new NetworkCredential("emailit", apiKey),
};
client.Send(new MailMessage("orders@acme.com", "ada@example.com", "Order confirmed", "We've received your order."));Per tutte le porte, vedi Impostazioni SMTP.
Ricevi i webhook
Crea un webhook e salva il suo secret di firma come Emailit:WebhookSecret. Leggi il corpo grezzo, verificalo, poi analizza l’array di eventi:
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;
app.MapPost("/webhooks/emailit", async (HttpRequest request, IConfiguration config) =>
{
using var reader = new StreamReader(request.Body, Encoding.UTF8);
var body = await reader.ReadToEndAsync();
var signature = request.Headers["X-Emailit-Signature"].ToString();
var timestamp = request.Headers["X-Emailit-Timestamp"].ToString();
if (!long.TryParse(timestamp, out var ts) ||
Math.Abs(DateTimeOffset.UtcNow.ToUnixTimeSeconds() - ts) > 300)
{
return Results.Unauthorized();
}
using var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(config["Emailit:WebhookSecret"]!));
var expected = Convert.ToHexString(hmac.ComputeHash(Encoding.UTF8.GetBytes($"{timestamp}.{body}"))).ToLowerInvariant();
if (!CryptographicOperations.FixedTimeEquals(Encoding.UTF8.GetBytes(expected), Encoding.UTF8.GetBytes(signature)))
{
return Results.Unauthorized();
}
// The body is a JSON array of up to 100 events.
using var events = JsonDocument.Parse(body);
foreach (var evt in events.RootElement.EnumerateArray())
{
if (evt.GetProperty("type").GetString() == "email.bounced")
{
var address = evt.GetProperty("data").GetProperty("object").GetProperty("to").GetString();
// Stop emailing this address.
}
}
return Results.Ok();
});Restituisci un 2xx entro 30 secondi; le altre risposte vengono ritentate. Vedi Firma delle richieste.
Consigli per la produzione
- Registra il client come singleton. Basta un
EmailitClientper app. - Metti in coda gli invii massivi. Invia da un
BackgroundServiceo da una libreria di job come Hangfire, e limita la velocità per restare entro i limiti di invio (2 email al secondo per impostazione predefinita). - Rendi sicuri i nuovi tentativi. Se ritenti dopo un timeout, invia un header
Idempotency-KeyconHttpClient; vedi Idempotenza. - Elimina i webhook duplicati salvando ogni
event_idche elabori.