Tutorial
Enviar e-mails com .NET
Envie e-mails do ASP.NET Core e do .NET com o pacote NuGet do Emailit, com MailKit ou com System.Net.Mail por SMTP, e verifique os webhooks do Emailit.
Este guia mostra como enviar e-mails de uma aplicação .NET com o pacote NuGet oficial Emailit, como usar MailKit ou System.Net.Mail por SMTP como alternativa e como verificar webhooks em uma minimal API do ASP.NET Core.
Pré-requisitos
- .NET 8 ou mais recente.
- Um domínio de envio verificado, por exemplo,
acme.com. - Uma chave de API. Uma chave Sending Only restrita ao seu domínio é suficiente.
- Até o seu workspace ter acesso de produção, você só pode enviar para os e-mails das contas dos membros do workspace.
Instalar o SDK
dotnet add package EmailitConfigurar a chave de API
O ASP.NET Core lê a configuração de variáveis de ambiente, em que __ separa as seções. Defina Emailit__ApiKey em produção:
export Emailit__ApiKey=secret_••••••••••••••••••••••••••••••••Durante o desenvolvimento, guarde a chave nos user secrets em vez de no appsettings.json:
dotnet user-secrets init
dotnet user-secrets set "Emailit:ApiKey" "secret_••••••••••••••••••••••••••••••••"Enviar um e-mail
Registre um único cliente e injete-o nos seus endpoints:
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 é síncrono; para envios em massa, execute-o a partir de um serviço em segundo plano para manter as threads de requisição livres. As opções também aceitam Cc, Bcc, ReplyTo, Attachments, Template com Variables, ScheduledAt e Tracking; consulte Enviar um e-mail.
Se o seu código já monta objetos System.Net.Mail.MailMessage, o SDK pode enviá-los pela 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);Tratar erros
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);
}Enviar por SMTP como alternativa
MailKit
A Microsoft recomenda o MailKit para código SMTP novo. Instale-o com 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);Para TLS implícito, conecte-se à porta 465 com SecureSocketOptions.SslOnConnect.
System.Net.Mail
O cliente nativo funciona para casos simples. Ele só aceita STARTTLS, então use a porta 587 (ou 2525 ou 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."));Consulte Configurações de SMTP para ver todas as portas.
Receber webhooks
Crie um webhook e guarde o segredo de assinatura dele como Emailit:WebhookSecret. Leia o corpo bruto, verifique-o e depois interprete o array de eventos:
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();
});Retorne um 2xx em até 30 segundos; as outras respostas recebem novas tentativas. Consulte Assinatura das requisições.
Dicas para produção
- Registre o cliente como singleton. Um único
EmailitClientpor aplicação é suficiente. - Coloque os envios em massa em uma fila. Envie a partir de um
BackgroundServiceou de uma biblioteca de jobs como o Hangfire e limite o ritmo para ficar dentro dos seus limites de envio (2 e-mails por segundo por padrão). - Torne as novas tentativas seguras. Se você tentar de novo depois de um timeout, envie um cabeçalho
Idempotency-Keycom oHttpClient; consulte Idempotência. - Elimine webhooks duplicados guardando cada
event_idque você processa.