Nuuvify.CommonPack.Email
2.2.0-test.25102902
See the version list below for details.
dotnet add package Nuuvify.CommonPack.Email --version 2.2.0-test.25102902
NuGet\Install-Package Nuuvify.CommonPack.Email -Version 2.2.0-test.25102902
<PackageReference Include="Nuuvify.CommonPack.Email" Version="2.2.0-test.25102902" />
<PackageVersion Include="Nuuvify.CommonPack.Email" Version="2.2.0-test.25102902" />
<PackageReference Include="Nuuvify.CommonPack.Email" />
paket add Nuuvify.CommonPack.Email --version 2.2.0-test.25102902
#r "nuget: Nuuvify.CommonPack.Email, 2.2.0-test.25102902"
#:package Nuuvify.CommonPack.Email@2.2.0-test.25102902
#addin nuget:?package=Nuuvify.CommonPack.Email&version=2.2.0-test.25102902&prerelease
#tool nuget:?package=Nuuvify.CommonPack.Email&version=2.2.0-test.25102902&prerelease
Nuuvify.CommonPack.Email
Implementação robusta e completa de serviço de envio de e-mails usando MailKit. Fornece uma abstração de alto nível para envio de e-mails com suporte a templates HTML, anexos, múltiplos destinatários e configuração flexível via appsettings.json.
📋 Índice
- Funcionalidades
- Instalação
- Dependências
- Configuração
- Uso
- Exemplos Práticos
- API Reference
- Troubleshooting
- Changelog
Funcionalidades
🎯 Core Features
- ✅ Envio de E-mails via SMTP usando MailKit
- ✅ Templates HTML com substituição de variáveis
- ✅ Anexos (documentos, imagens, PDFs)
- ✅ Múltiplos Destinatários (To, Cc, Bcc)
- ✅ Configuração via appsettings.json para diferentes ambientes
- ✅ Notification Pattern para rastreamento de erros
- ✅ Suporte a SSL/TLS para comunicação segura
- ✅ Async/Await para operações não bloqueantes
🔒 Security Features
- ✅ SSL/TLS Encryption (None, SSL, TLS)
- ✅ Autenticação SMTP com usuário e senha
- ✅ Validação de configurações antes do envio
- ✅ Proteção de credenciais via configuration
📧 Email Features
- ✅ HTML e Text support
- ✅ Inline Images para templates
- ✅ Attachments com múltiplos tipos MIME
- ✅ Encoding UTF-8 automático
- ✅ Template Engine simples e eficaz
- ✅ Fluent API para construção de e-mails
🛠️ Advanced Features
- ✅ Stream Support para anexos dinâmicos
- ✅ Reset Instance para envio em lote
- ✅ Log Messages separado de notificações
- ✅ Validation automática de configurações
- ✅ Cancellation Token support
- ✅ Compatibilidade .NET Standard 2.1
Instalação
Via Package Manager Console
Install-Package Nuuvify.CommonPack.Email
Install-Package Nuuvify.CommonPack.Email.Abstraction
Via .NET CLI
dotnet add package Nuuvify.CommonPack.Email
dotnet add package Nuuvify.CommonPack.Email.Abstraction
Via PackageReference
<PackageReference Include="Nuuvify.CommonPack.Email" Version="X.X.X" />
<PackageReference Include="Nuuvify.CommonPack.Email.Abstraction" Version="X.X.X" />
Dependências
NuGet Packages
| Package | Version | Descrição |
|---|---|---|
| MailKit | Latest | Biblioteca completa para envio de e-mails SMTP |
| Microsoft.Extensions.Options.ConfigurationExtensions | Latest | Suporte ao padrão Options para configuração |
| Nuuvify.CommonPack.Email.Abstraction | - | Interfaces e abstrações do serviço de e-mail |
Framework
- .NET Standard 2.1: Compatível com .NET Core 3.0+, .NET 5+, .NET 6+, .NET 8+ e .NET Framework 4.7.2+
Configuração
1. Configurar appsettings.json
{
"EmailConfig": {
"EmailServerConfiguration": {
"ServerHost": "smtp.gmail.com",
"Port": 587,
"Security": "StartTls",
"AccountUserName": "seu-email@gmail.com",
"AccountPassword": "sua-senha-ou-app-password"
},
"RemetenteEmail": {
"email1": "noreply@empresa.com",
"nome1": "Empresa XYZ",
"email2": "suporte@empresa.com",
"nome2": "Suporte Técnico"
},
"DestinatariosEmail": {
"admin": "admin@empresa.com",
"suporte": "suporte@empresa.com"
}
}
}
2. Registrar Serviços (Dependency Injection)
// Program.cs (.NET 6+)
using Nuuvify.CommonPack.Email;
using Nuuvify.CommonPack.Email.Abstraction;
var builder = WebApplication.CreateBuilder(args);
// Registrar serviço de e-mail com configuração
builder.Services.AddScoped<IEmail, Email>();
builder.Services.Configure<EmailServerConfiguration>(
builder.Configuration.GetSection("EmailConfig:EmailServerConfiguration"));
var app = builder.Build();
app.Run();
// Startup.cs (.NET Core 3.1 / .NET 5)
public class Startup
{
public IConfiguration Configuration { get; }
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public void ConfigureServices(IServiceCollection services)
{
// Registrar serviço de e-mail
services.AddScoped<IEmail, Email>();
// Configurar servidor de e-mail via Options Pattern
services.Configure<EmailServerConfiguration>(
Configuration.GetSection("EmailConfig:EmailServerConfiguration"));
}
}
3. Configurações de Segurança SSL/TLS
using System.Security.Authentication;
// Opções de segurança disponíveis:
public enum SslProtocols
{
None = 0, // Sem criptografia (não recomendado)
Ssl2 = 12, // SSL 2.0 (obsoleto)
Ssl3 = 48, // SSL 3.0 (obsoleto)
Tls = 192, // TLS 1.0
Tls11 = 768, // TLS 1.1
Tls12 = 3072, // TLS 1.2 (recomendado)
Tls13 = 12288 // TLS 1.3 (mais recente)
}
Configurações para Provedores Comuns
Gmail
{
"ServerHost": "smtp.gmail.com",
"Port": 587,
"Security": "StartTls",
"AccountUserName": "seu-email@gmail.com",
"AccountPassword": "app-password-gerado-no-google"
}
⚠️ Importante: Para Gmail, use App Passwords ao invés da senha normal.
Outlook/Office 365
{
"ServerHost": "smtp-mail.outlook.com",
"Port": 587,
"Security": "StartTls",
"AccountUserName": "seu-email@outlook.com",
"AccountPassword": "sua-senha"
}
SendGrid
{
"ServerHost": "smtp.sendgrid.net",
"Port": 587,
"Security": "StartTls",
"AccountUserName": "apikey",
"AccountPassword": "SG.sua-api-key-aqui"
}
Amazon SES
{
"ServerHost": "email-smtp.us-east-1.amazonaws.com",
"Port": 587,
"Security": "StartTls",
"AccountUserName": "suas-credenciais-smtp",
"AccountPassword": "sua-senha-smtp"
}
Uso
Envio Básico
using Nuuvify.CommonPack.Email.Abstraction;
public class NotificationService
{
private readonly IEmail _emailService;
private readonly IConfiguration _configuration;
public NotificationService(IEmail emailService, IConfiguration configuration)
{
_emailService = emailService;
_configuration = configuration;
}
public async Task EnviarEmailSimples()
{
// Preparar destinatários
var recipients = new Dictionary<string, string>
{
{ "destinatario@exemplo.com", "João Silva" }
};
// Preparar remetentes
var senders = new Dictionary<string, string>
{
{ "noreply@empresa.com", "Empresa XYZ" }
};
// Assunto e mensagem
var subject = "Bem-vindo à Empresa XYZ";
var message = "<h1>Olá, João!</h1><p>Seja bem-vindo à nossa plataforma.</p>";
// Enviar e-mail
var result = await _emailService.EnviarAsync(
recipients: recipients,
senders: senders,
subject: subject,
message: message
);
// Verificar se houve erros
if (!_emailService.IsValid())
{
foreach (var notification in _emailService.Notifications)
{
Console.WriteLine($"Erro: {notification.Property} - {notification.Message}");
}
}
}
}
Templates HTML
Criar Template HTML
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
body { font-family: Arial, sans-serif; }
.header { background-color: #007bff; color: white; padding: 20px; }
.content { padding: 20px; }
.footer { background-color: #f8f9fa; padding: 10px; text-align: center; }
</style>
</head>
<body>
<div class="header">
<h1>Bem-vindo, {{NOME_CLIENTE}}!</h1>
</div>
<div class="content">
<p>Olá {{NOME_CLIENTE}},</p>
<p>Seu cadastro foi realizado com sucesso em {{DATA_CADASTRO}}.</p>
<p>Sua conta: <strong>{{NUMERO_CONTA}}</strong></p>
<p>Para acessar o sistema, use o seguinte link:</p>
<p><a href="{{LINK_ACESSO}}">Acessar Sistema</a></p>
</div>
<div class="footer">
<p>© {{ANO}} Empresa XYZ. Todos os direitos reservados.</p>
</div>
</body>
</html>
Usar Template
public class TemplateEmailService
{
private readonly IEmail _emailService;
private readonly IWebHostEnvironment _environment;
public TemplateEmailService(IEmail emailService, IWebHostEnvironment environment)
{
_emailService = emailService;
_environment = environment;
}
public async Task EnviarEmailComTemplate(string nomeCliente, string emailCliente)
{
// Caminho do template
var templatePath = Path.Combine(
_environment.ContentRootPath,
"Templates",
"boas-vindas.html"
);
// Variáveis a serem substituídas
var variables = new Dictionary<string, string>
{
{ "{{NOME_CLIENTE}}", nomeCliente },
{ "{{DATA_CADASTRO}}", DateTime.Now.ToString("dd/MM/yyyy") },
{ "{{NUMERO_CONTA}}", "123456789" },
{ "{{LINK_ACESSO}}", "https://www.empresa.com/login" },
{ "{{ANO}}", DateTime.Now.Year.ToString() }
};
// Processar template
var htmlMessage = _emailService.GetEmailTemplate(
variables: variables,
templateFullName: templatePath
);
// Preparar destinatários
var recipients = new Dictionary<string, string>
{
{ emailCliente, nomeCliente }
};
var senders = new Dictionary<string, string>
{
{ "noreply@empresa.com", "Empresa XYZ" }
};
// Enviar e-mail com template
await _emailService.EnviarAsync(
recipients: recipients,
senders: senders,
subject: "Bem-vindo à Empresa XYZ",
message: htmlMessage
);
}
}
Anexos
public class EmailComAnexosService
{
private readonly IEmail _emailService;
public EmailComAnexosService(IEmail emailService)
{
_emailService = emailService;
}
public async Task EnviarEmailComAnexos()
{
var recipients = new Dictionary<string, string>
{
{ "cliente@exemplo.com", "Cliente" }
};
var senders = new Dictionary<string, string>
{
{ "noreply@empresa.com", "Empresa XYZ" }
};
// Anexar PDF
_emailService.WithAttachment(
pathFileFullName: @"C:\Documentos\relatorio.pdf",
midiaType: EmailMidiaType.Application,
midiaSubType: EmailMidiaSubType.Pdf
);
// Anexar imagem
_emailService.WithAttachment(
pathFileFullName: @"C:\Imagens\logo.png",
midiaType: EmailMidiaType.Image,
midiaSubType: EmailMidiaSubType.Png
);
// Anexar arquivo de texto
_emailService.WithAttachment(
pathFileFullName: @"C:\Documentos\informacoes.txt",
midiaType: EmailMidiaType.Text,
midiaSubType: EmailMidiaSubType.Text
);
// Verificar quantidade de anexos
var totalAnexos = _emailService.CountAttachments();
Console.WriteLine($"Total de anexos: {totalAnexos}");
// Enviar e-mail
await _emailService.EnviarAsync(
recipients: recipients,
senders: senders,
subject: "Documentos Anexados",
message: "<p>Segue em anexo os documentos solicitados.</p>"
);
// Limpar anexos para próximo envio
_emailService.RemoveAllAttachments();
}
public async Task EnviarEmailComAnexoStream()
{
// Criar arquivo em memória
var stream = new MemoryStream();
var writer = new StreamWriter(stream);
writer.Write("Conteúdo do relatório dinâmico");
writer.Flush();
stream.Position = 0;
// Anexar stream
_emailService.WithAttachment(
fileStream: stream,
midiaType: EmailMidiaType.Text,
midiaSubType: EmailMidiaSubType.Text,
fullFileName: "relatorio-dinamico.txt"
);
var recipients = new Dictionary<string, string>
{
{ "cliente@exemplo.com", "Cliente" }
};
var senders = new Dictionary<string, string>
{
{ "noreply@empresa.com", "Empresa XYZ" }
};
await _emailService.EnviarAsync(
recipients: recipients,
senders: senders,
subject: "Relatório Dinâmico",
message: "<p>Segue relatório gerado automaticamente.</p>"
);
// Limpar recursos
stream.Dispose();
_emailService.RemoveAllAttachments();
}
}
Múltiplos Destinatários
public class EmailMultiplosDestinatariosService
{
private readonly IEmail _emailService;
private readonly IConfiguration _configuration;
public EmailMultiplosDestinatariosService(
IEmail emailService,
IConfiguration configuration)
{
_emailService = emailService;
_configuration = configuration;
}
public async Task EnviarParaMultiplosDestinatarios()
{
// Ler destinatários do appsettings.json
var destinatarios = _configuration
.GetSection("EmailConfig:DestinatariosEmail")
.GetChildren()
.ToDictionary(x => x.Key, x => x.Value);
// Ou criar manualmente
var recipients = new Dictionary<string, string>
{
{ "destinatario1@exemplo.com", "João Silva" },
{ "destinatario2@exemplo.com", "Maria Santos" },
{ "destinatario3@exemplo.com", "Pedro Oliveira" }
};
var senders = new Dictionary<string, string>
{
{ "noreply@empresa.com", "Empresa XYZ" }
};
await _emailService.EnviarAsync(
recipients: recipients,
senders: senders,
subject: "Comunicado Importante",
message: "<h1>Comunicado</h1><p>Informamos que...</p>"
);
}
public async Task EnviarEmailsIndividuais()
{
var listaClientes = new List<(string Email, string Nome)>
{
("cliente1@exemplo.com", "Cliente 1"),
("cliente2@exemplo.com", "Cliente 2"),
("cliente3@exemplo.com", "Cliente 3")
};
var senders = new Dictionary<string, string>
{
{ "noreply@empresa.com", "Empresa XYZ" }
};
foreach (var cliente in listaClientes)
{
// Resetar instância para novo envio
_emailService.ResetMailInstance();
var recipients = new Dictionary<string, string>
{
{ cliente.Email, cliente.Nome }
};
var message = $"<p>Olá {cliente.Nome},</p><p>Mensagem personalizada...</p>";
await _emailService.EnviarAsync(
recipients: recipients,
senders: senders,
subject: $"Mensagem para {cliente.Nome}",
message: message
);
// Verificar erros
if (!_emailService.IsValid())
{
Console.WriteLine($"Erro ao enviar para {cliente.Email}");
foreach (var notification in _emailService.Notifications)
{
Console.WriteLine($" - {notification.Message}");
}
_emailService.RemoveAllNotifications();
}
}
}
}
Notificações e Logging
public class EmailComLoggingService
{
private readonly IEmail _emailService;
private readonly ILogger<EmailComLoggingService> _logger;
public EmailComLoggingService(
IEmail emailService,
ILogger<EmailComLoggingService> logger)
{
_emailService = emailService;
_logger = logger;
}
public async Task<bool> EnviarComValidacao()
{
var recipients = new Dictionary<string, string>
{
{ "cliente@exemplo.com", "Cliente" }
};
var senders = new Dictionary<string, string>
{
{ "noreply@empresa.com", "Empresa XYZ" }
};
try
{
await _emailService.EnviarAsync(
recipients: recipients,
senders: senders,
subject: "Teste de E-mail",
message: "<p>Conteúdo do e-mail</p>"
);
// Verificar validação
if (!_emailService.IsValid())
{
// Logar erros (Notifications)
foreach (var notification in _emailService.Notifications)
{
_logger.LogError(
"Erro ao enviar e-mail: {Property} - {Message}",
notification.Property,
notification.Message
);
}
return false;
}
// Logar mensagens informativas (LogMessage)
foreach (var logMsg in _emailService.LogMessage)
{
_logger.LogInformation(
"Log de e-mail: {Property} - {Message}",
logMsg.Property,
logMsg.Message
);
}
_logger.LogInformation("E-mail enviado com sucesso para {Count} destinatários",
recipients.Count);
return true;
}
catch (Exception ex)
{
_logger.LogError(ex, "Exceção ao enviar e-mail");
return false;
}
finally
{
// Limpar notificações e logs
_emailService.RemoveAllNotifications();
_emailService.RemoveAllLogMessage();
}
}
public async Task EnviarComRetry(int maxRetries = 3)
{
var recipients = new Dictionary<string, string>
{
{ "cliente@exemplo.com", "Cliente" }
};
var senders = new Dictionary<string, string>
{
{ "noreply@empresa.com", "Empresa XYZ" }
};
int tentativa = 0;
bool sucesso = false;
while (tentativa < maxRetries && !sucesso)
{
tentativa++;
_logger.LogInformation("Tentativa {Tentativa} de {MaxTentativas}",
tentativa, maxRetries);
try
{
await _emailService.EnviarAsync(
recipients: recipients,
senders: senders,
subject: "E-mail com Retry",
message: "<p>Conteúdo</p>"
);
if (_emailService.IsValid())
{
sucesso = true;
_logger.LogInformation("E-mail enviado com sucesso na tentativa {Tentativa}",
tentativa);
}
else
{
_logger.LogWarning("Falha na tentativa {Tentativa}. Erros: {Erros}",
tentativa,
string.Join(", ", _emailService.Notifications.Select(n => n.Message))
);
_emailService.RemoveAllNotifications();
}
}
catch (Exception ex)
{
_logger.LogError(ex, "Erro na tentativa {Tentativa}", tentativa);
}
if (!sucesso && tentativa < maxRetries)
{
await Task.Delay(TimeSpan.FromSeconds(5 * tentativa)); // Backoff exponencial
}
}
if (!sucesso)
{
_logger.LogError("Falha ao enviar e-mail após {MaxTentativas} tentativas",
maxRetries);
}
}
}
Exemplos Práticos
Exemplo 1: Sistema de Boas-Vindas
public class WelcomeEmailService
{
private readonly IEmail _emailService;
private readonly IWebHostEnvironment _environment;
private readonly ILogger<WelcomeEmailService> _logger;
public WelcomeEmailService(
IEmail emailService,
IWebHostEnvironment environment,
ILogger<WelcomeEmailService> logger)
{
_emailService = emailService;
_environment = environment;
_logger = logger;
}
public async Task<bool> EnviarBoasVindasAsync(
string nomeUsuario,
string emailUsuario,
string tokenAtivacao)
{
try
{
// Caminho do template
var templatePath = Path.Combine(
_environment.ContentRootPath,
"Templates",
"Email",
"boas-vindas.html"
);
// Variáveis do template
var variables = new Dictionary<string, string>
{
{ "{{NOME_USUARIO}}", nomeUsuario },
{ "{{EMAIL_USUARIO}}", emailUsuario },
{ "{{DATA_CADASTRO}}", DateTime.Now.ToString("dd/MM/yyyy HH:mm") },
{ "{{LINK_ATIVACAO}}", $"https://www.empresa.com/ativar?token={tokenAtivacao}" },
{ "{{ANO}}", DateTime.Now.Year.ToString() }
};
// Processar template
var htmlMessage = _emailService.GetEmailTemplate(variables, templatePath);
// Anexar manual do usuário
var manualPath = Path.Combine(
_environment.ContentRootPath,
"Documents",
"manual-usuario.pdf"
);
if (File.Exists(manualPath))
{
_emailService.WithAttachment(
pathFileFullName: manualPath,
midiaType: EmailMidiaType.Application,
midiaSubType: EmailMidiaSubType.Pdf
);
}
// Preparar destinatários e remetentes
var recipients = new Dictionary<string, string>
{
{ emailUsuario, nomeUsuario }
};
var senders = new Dictionary<string, string>
{
{ "noreply@empresa.com", "Equipe Empresa XYZ" }
};
// Enviar e-mail
await _emailService.EnviarAsync(
recipients: recipients,
senders: senders,
subject: $"Bem-vindo(a) à Empresa XYZ, {nomeUsuario}!",
message: htmlMessage
);
// Validar envio
if (!_emailService.IsValid())
{
_logger.LogError(
"Erro ao enviar e-mail de boas-vindas para {Email}. Erros: {Erros}",
emailUsuario,
string.Join(", ", _emailService.Notifications.Select(n => n.Message))
);
return false;
}
_logger.LogInformation(
"E-mail de boas-vindas enviado com sucesso para {Nome} ({Email})",
nomeUsuario,
emailUsuario
);
return true;
}
catch (Exception ex)
{
_logger.LogError(ex, "Exceção ao enviar e-mail de boas-vindas para {Email}",
emailUsuario);
return false;
}
finally
{
_emailService.RemoveAllAttachments();
_emailService.RemoveAllNotifications();
_emailService.RemoveAllLogMessage();
}
}
}
Exemplo 2: Notificações de Pedidos
public class OrderNotificationService
{
private readonly IEmail _emailService;
private readonly IWebHostEnvironment _environment;
public OrderNotificationService(
IEmail emailService,
IWebHostEnvironment environment)
{
_emailService = emailService;
_environment = environment;
}
public async Task NotificarNovoPedidoAsync(Order order)
{
// Template para cliente
var clienteTemplatePath = Path.Combine(
_environment.ContentRootPath,
"Templates",
"Email",
"confirmacao-pedido.html"
);
var clienteVariables = new Dictionary<string, string>
{
{ "{{NOME_CLIENTE}}", order.CustomerName },
{ "{{NUMERO_PEDIDO}}", order.OrderNumber },
{ "{{DATA_PEDIDO}}", order.OrderDate.ToString("dd/MM/yyyy HH:mm") },
{ "{{VALOR_TOTAL}}", order.TotalAmount.ToString("C2") },
{ "{{ITENS_PEDIDO}}", GerarHtmlItensPedido(order.Items) },
{ "{{LINK_ACOMPANHAMENTO}}", $"https://www.empresa.com/pedidos/{order.Id}" }
};
var clienteHtml = _emailService.GetEmailTemplate(
clienteVariables,
clienteTemplatePath
);
// Gerar PDF do pedido
var pdfStream = GerarPdfPedido(order);
_emailService.WithAttachment(
fileStream: pdfStream,
midiaType: EmailMidiaType.Application,
midiaSubType: EmailMidiaSubType.Pdf,
fullFileName: $"pedido-{order.OrderNumber}.pdf"
);
// Enviar para cliente
var clienteRecipients = new Dictionary<string, string>
{
{ order.CustomerEmail, order.CustomerName }
};
var senders = new Dictionary<string, string>
{
{ "vendas@empresa.com", "Equipe de Vendas - Empresa XYZ" }
};
await _emailService.EnviarAsync(
recipients: clienteRecipients,
senders: senders,
subject: $"Pedido #{order.OrderNumber} - Confirmação",
message: clienteHtml
);
// Limpar para próximo envio
_emailService.ResetMailInstance();
// Notificar equipe de vendas
var vendedoresRecipients = new Dictionary<string, string>
{
{ "vendas@empresa.com", "Equipe de Vendas" },
{ "gerencia@empresa.com", "Gerência" }
};
var vendedoresHtml = $@"
<h2>Novo Pedido Recebido</h2>
<p><strong>Pedido:</strong> {order.OrderNumber}</p>
<p><strong>Cliente:</strong> {order.CustomerName}</p>
<p><strong>Valor:</strong> {order.TotalAmount:C2}</p>
<p><a href='https://admin.empresa.com/pedidos/{order.Id}'>Ver Detalhes</a></p>
";
await _emailService.EnviarAsync(
recipients: vendedoresRecipients,
senders: senders,
subject: $"[Novo Pedido] #{order.OrderNumber} - {order.CustomerName}",
message: vendedoresHtml
);
// Cleanup
pdfStream.Dispose();
_emailService.RemoveAllAttachments();
_emailService.RemoveAllNotifications();
}
private string GerarHtmlItensPedido(List<OrderItem> items)
{
var html = new StringBuilder();
html.Append("<table style='width:100%; border-collapse: collapse;'>");
html.Append("<thead><tr>");
html.Append("<th style='border:1px solid #ddd; padding:8px;'>Produto</th>");
html.Append("<th style='border:1px solid #ddd; padding:8px;'>Qtd</th>");
html.Append("<th style='border:1px solid #ddd; padding:8px;'>Valor Unit.</th>");
html.Append("<th style='border:1px solid #ddd; padding:8px;'>Total</th>");
html.Append("</tr></thead><tbody>");
foreach (var item in items)
{
html.Append("<tr>");
html.Append($"<td style='border:1px solid #ddd; padding:8px;'>{item.ProductName}</td>");
html.Append($"<td style='border:1px solid #ddd; padding:8px; text-align:center;'>{item.Quantity}</td>");
html.Append($"<td style='border:1px solid #ddd; padding:8px; text-align:right;'>{item.UnitPrice:C2}</td>");
html.Append($"<td style='border:1px solid #ddd; padding:8px; text-align:right;'>{item.TotalPrice:C2}</td>");
html.Append("</tr>");
}
html.Append("</tbody></table>");
return html.ToString();
}
private MemoryStream GerarPdfPedido(Order order)
{
// Implementação simplificada - use uma biblioteca de PDF real
var stream = new MemoryStream();
var writer = new StreamWriter(stream);
writer.WriteLine($"Pedido: {order.OrderNumber}");
writer.WriteLine($"Cliente: {order.CustomerName}");
writer.WriteLine($"Total: {order.TotalAmount:C2}");
writer.Flush();
stream.Position = 0;
return stream;
}
}
Exemplo 3: Newsletter em Lote
public class NewsletterService
{
private readonly IEmail _emailService;
private readonly IWebHostEnvironment _environment;
private readonly ILogger<NewsletterService> _logger;
public NewsletterService(
IEmail emailService,
IWebHostEnvironment environment,
ILogger<NewsletterService> logger)
{
_emailService = emailService;
_environment = environment;
_logger = logger;
}
public async Task<NewsletterResult> EnviarNewsletterAsync(
string tituloNewsletter,
string conteudoHtml,
List<Subscriber> subscribers)
{
var result = new NewsletterResult
{
TotalSubscribers = subscribers.Count,
StartTime = DateTime.Now
};
var senders = new Dictionary<string, string>
{
{ "newsletter@empresa.com", "Newsletter Empresa XYZ" }
};
foreach (var subscriber in subscribers)
{
try
{
// Resetar instância para cada envio
_emailService.ResetMailInstance();
// Personalizar conteúdo para cada assinante
var conteudoPersonalizado = conteudoHtml
.Replace("{{NOME}}", subscriber.Name)
.Replace("{{EMAIL}}", subscriber.Email)
.Replace("{{LINK_CANCELAR}}",
$"https://www.empresa.com/newsletter/cancelar?token={subscriber.UnsubscribeToken}");
var recipients = new Dictionary<string, string>
{
{ subscriber.Email, subscriber.Name }
};
await _emailService.EnviarAsync(
recipients: recipients,
senders: senders,
subject: tituloNewsletter,
message: conteudoPersonalizado
);
if (_emailService.IsValid())
{
result.SuccessCount++;
_logger.LogDebug("Newsletter enviada para {Email}", subscriber.Email);
}
else
{
result.FailureCount++;
result.FailedEmails.Add(subscriber.Email);
_logger.LogWarning(
"Falha ao enviar newsletter para {Email}. Erros: {Erros}",
subscriber.Email,
string.Join(", ", _emailService.Notifications.Select(n => n.Message))
);
}
// Delay para evitar sobrecarga do servidor SMTP
await Task.Delay(100);
}
catch (Exception ex)
{
result.FailureCount++;
result.FailedEmails.Add(subscriber.Email);
_logger.LogError(ex, "Exceção ao enviar newsletter para {Email}",
subscriber.Email);
}
finally
{
_emailService.RemoveAllNotifications();
_emailService.RemoveAllLogMessage();
}
}
result.EndTime = DateTime.Now;
result.Duration = result.EndTime - result.StartTime;
_logger.LogInformation(
"Newsletter finalizada. Enviados: {Success}, Falhas: {Failures}, Duração: {Duration}",
result.SuccessCount,
result.FailureCount,
result.Duration
);
return result;
}
}
public class NewsletterResult
{
public int TotalSubscribers { get; set; }
public int SuccessCount { get; set; }
public int FailureCount { get; set; }
public List<string> FailedEmails { get; set; } = new List<string>();
public DateTime StartTime { get; set; }
public DateTime EndTime { get; set; }
public TimeSpan Duration { get; set; }
}
public class Subscriber
{
public string Name { get; set; }
public string Email { get; set; }
public string UnsubscribeToken { get; set; }
}
API Reference
IEmail Interface
public interface IEmail
{
// Propriedades
List<NotificationR> Notifications { get; set; }
List<NotificationR> LogMessage { get; set; }
EmailServerConfiguration EmailServerConfiguration { get; set; }
// Métodos de validação
bool IsValid();
// Envio de e-mail
Task<object> EnviarAsync(
Dictionary<string, string> recipients,
Dictionary<string, string> senders,
string subject,
string message,
CancellationToken cancellationToken = default);
// Templates
string GetEmailTemplate(
Dictionary<string, string> variables,
string templateFullName);
// Anexos
IEmail WithAttachment(
string pathFileFullName,
EmailMidiaType midiaType,
EmailMidiaSubType midiaSubType);
IEmail WithAttachment(
Stream fileStream,
EmailMidiaType midiaType,
EmailMidiaSubType midiaSubType,
string fullFileName);
int CountAttachments();
IEmail RemoveAllAttachments();
// Gerenciamento
IEmail RemoveAllLogMessage();
IEmail RemoveAllNotifications();
void ResetMailInstance();
}
EmailServerConfiguration
public class EmailServerConfiguration
{
public string ServerHost { get; set; }
public int Port { get; set; }
public SslProtocols Security { get; set; }
public string AccountUserName { get; set; }
public string AccountPassword { get; set; }
}
EmailMidiaType & EmailMidiaSubType
public enum EmailMidiaType
{
Text, // Arquivos de texto
Image, // Imagens
Application // Documentos (PDF, etc.)
}
public enum EmailMidiaSubType
{
Text, // .txt
Gif, // .gif
Jpg, // .jpg, .jpeg
Png, // .png
Pdf // .pdf
}
PessoasEmail
public enum PessoasEmail
{
From = 0, // Remetente
To = 1, // Destinatário
Cc = 2, // Com Cópia
Bcc = 3 // Com Cópia Oculta
}
Troubleshooting
Problemas Comuns
1. Falha na autenticação SMTP
Problema: Erro "Authentication failed" ao enviar e-mail
Causas Comuns:
- Credenciais incorretas
- Gmail bloqueando "apps menos seguros"
- 2FA habilitado sem App Password
Solução:
// Para Gmail, use App Passwords
{
"EmailServerConfiguration": {
"ServerHost": "smtp.gmail.com",
"Port": 587,
"Security": "StartTls",
"AccountUserName": "seu-email@gmail.com",
"AccountPassword": "xxxx xxxx xxxx xxxx" // App Password de 16 dígitos
}
}
2. E-mails não são enviados
Problema: Método EnviarAsync() executa mas e-mails não chegam
Solução: Verificar notificações
await _emailService.EnviarAsync(recipients, senders, subject, message);
if (!_emailService.IsValid())
{
// Verificar erros
foreach (var notification in _emailService.Notifications)
{
Console.WriteLine($"Erro: {notification.Message}");
}
}
3. Anexos não aparecem
Problema: E-mail enviado mas anexos não estão presentes
Causa: Caminho do arquivo incorreto ou tipo MIME errado
Solução:
// Verificar se arquivo existe
var filePath = @"C:\Docs\file.pdf";
if (!File.Exists(filePath))
{
throw new FileNotFoundException($"Arquivo não encontrado: {filePath}");
}
// Usar tipo MIME correto
_emailService.WithAttachment(
pathFileFullName: filePath,
midiaType: EmailMidiaType.Application, // Para PDFs
midiaSubType: EmailMidiaSubType.Pdf
);
// Verificar se foi anexado
var count = _emailService.CountAttachments();
Console.WriteLine($"Total de anexos: {count}");
4. Template não substitui variáveis
Problema: Variáveis como {{NOME}} aparecem literalmente no e-mail
Causa: Variáveis não correspondem às do template
Solução:
// ✅ Correto - Variáveis exatamente como no template
var variables = new Dictionary<string, string>
{
{ "{{NOME}}", "João" }, // Incluir {{ }}
{ "{{EMAIL}}", "joao@email.com" }
};
// ❌ Incorreto
var variables = new Dictionary<string, string>
{
{ "NOME", "João" }, // Faltam {{ }}
{ "EMAIL", "joao@email.com" }
};
5. Erro de conexão SSL/TLS
Problema: "The remote certificate is invalid"
Causa: Problemas com certificado SSL
Solução:
// Ajustar protocolo de segurança
{
"Security": "StartTls" // Ou "Tls12" dependendo do servidor
}
// Para desenvolvimento (NÃO usar em produção)
// Adicionar callback para ignorar erros de certificado
6. Timeout ao enviar e-mail
Problema: Operação demora muito ou timeout
Causa: Servidor SMTP lento ou problema de rede
Solução:
// Usar CancellationToken com timeout
var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));
try
{
await _emailService.EnviarAsync(
recipients,
senders,
subject,
message,
cts.Token
);
}
catch (OperationCanceledException)
{
_logger.LogError("Timeout ao enviar e-mail");
}
Logs e Debugging
Para debugging detalhado:
public class EmailDebugService
{
private readonly IEmail _emailService;
private readonly ILogger<EmailDebugService> _logger;
public async Task EnviarComDebugAsync()
{
_logger.LogInformation("Iniciando envio de e-mail");
// Log configuração (sem senha!)
var config = _emailService.EmailServerConfiguration;
_logger.LogInformation(
"Configuração: {Host}:{Port}, Security: {Security}",
config.ServerHost,
config.Port,
config.Security
);
await _emailService.EnviarAsync(recipients, senders, subject, message);
// Log resultado
_logger.LogInformation("Notificações: {Count}", _emailService.Notifications.Count);
_logger.LogInformation("Log Messages: {Count}", _emailService.LogMessage.Count);
_logger.LogInformation("Anexos: {Count}", _emailService.CountAttachments());
// Log detalhado de erros
foreach (var notification in _emailService.Notifications)
{
_logger.LogError(
"Notificação - Property: {Property}, Message: {Message}, Time: {Time}",
notification.Property,
notification.Message,
notification.DateOccurrence
);
}
// Log de mensagens informativas
foreach (var logMsg in _emailService.LogMessage)
{
_logger.LogInformation(
"LogMessage - Property: {Property}, Message: {Message}",
logMsg.Property,
logMsg.Message
);
}
}
}
Changelog
Ver arquivo CHANGELOG.md para histórico detalhado de alterações.
📞 Suporte
Para dúvidas, issues ou contribuições:
- 🐛 Issues: GitHub Issues
- 📧 Email: suporte@zocate.li
- 📖 Documentação: Wiki do Projeto
Nuuvify CommonPack - Construindo soluções robustas para .NET 🚀
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.1 is compatible. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.1
- MailKit (>= 4.8.0)
- Microsoft.Extensions.Options.ConfigurationExtensions (>= 8.0.0)
- Nuuvify.CommonPack.Email.Abstraction (>= 2.2.0-test.25102902)
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 3.0.0-test.25052502 | 0 | 5/25/2025 |
| 3.0.0-test.25050204 | 0 | 5/2/2025 |
| 3.0.0-test.25042801 | 0 | 4/28/2025 |
| 3.0.0-test.25042712 | 0 | 4/28/2025 |
| 3.0.0-test.25042711 | 0 | 4/28/2025 |
| 3.0.0-test.25042709 | 0 | 4/28/2025 |
| 3.0.0-test.25042708 | 0 | 4/28/2025 |
| 3.0.0-test.25042707 | 0 | 4/28/2025 |
| 3.0.0-test.25042705 | 0 | 4/28/2025 |
| 3.0.0-test.25042703 | 0 | 4/28/2025 |
| 3.0.0-test.25042701 | 0 | 4/27/2025 |
| 3.0.0-test.25041702 | 1 | 4/17/2025 |
| 2.2.0-test.25102902 | 0 | 10/29/2025 |
| 2.1.0-test.25101302 | 137 | 10/13/2025 |
| 2.1.0-test.25101102 | 1 | 10/12/2025 |
| 2.1.0-test.25100702 | 2 | 10/8/2025 |
| 2.1.0-test.25100602 | 11 | 10/6/2025 |
| 2.1.0-test.25100507 | 1 | 10/6/2025 |
| 2.1.0-test.25100503 | 1 | 10/5/2025 |
| 2.1.0-test.25093008 | 1 | 9/30/2025 |
| 2.0.0-preview.25041508 | 0 | 4/16/2025 |
| 2.0.0-preview.25041506 | 43 | 4/16/2025 |
# Changelog - Nuuvify.CommonPack.Email
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
### Planned Features
- [ ] Suporte a templates Razor para e-mails dinâmicos
- [ ] Rate limiting para envio em lote
- [ ] Queue system para processamento assíncrono
- [ ] Métricas e telemetria de envio
- [ ] Suporte a provedores alternativos (SendGrid SDK, AWS SES SDK)
- [ ] Internacionalização (i18n) de templates
- [ ] Editor visual de templates
- [ ] Webhooks para eventos de e-mail (entregue, aberto, clicado)
- [ ] Suporte a imagens inline (embedded images)
- [ ] Validação avançada de e-mails
---
## [1.0.0] - Current Version
### Features
#### Core Email Functionality
- ✅ **Envio SMTP via MailKit**: Implementação robusta usando MailKit para máxima compatibilidade
- ✅ **Async/Await**: Suporte completo a operações assíncronas com `EnviarAsync()`
- ✅ **CancellationToken**: Permite cancelamento de operações de envio
- ✅ **SSL/TLS Support**: Protocolos de segurança configuráveis (None, SSL2, SSL3, TLS, TLS11, TLS12, TLS13)
- ✅ **Autenticação SMTP**: Suporte a autenticação com username/password
- ✅ **Encoding UTF-8**: Suporte completo a caracteres especiais e acentuação
#### Template System
- ✅ **HTML Templates**: Processamento de templates HTML com substituição de variáveis
- ✅ **Variable Substitution**: Sistema de placeholders `{{VARIAVEL}}` para personalização
- ✅ **File-based Templates**: Suporte a arquivos `.html` externos
- ✅ **Dynamic Content**: Geração dinâmica de conteúdo via `GetEmailTemplate()`
#### Attachment Support
- ✅ **File Attachments**: Anexar arquivos via caminho completo
- ✅ **Stream Attachments**: Anexar arquivos via `Stream` para cenários dinâmicos
- ✅ **Multiple MIME Types**: Suporte a Text, Image, Application
- ✅ **Multiple Subtypes**: Text, GIF, JPG, PNG, PDF
- ✅ **Attachment Management**: Métodos para adicionar, contar e remover anexos
- ✅ **Fluent API**: `WithAttachment()` com retorno de `IEmail` para chaining
#### Recipient Management
- ✅ **Multiple Recipients**: Suporte a múltiplos destinatários via `Dictionary<string, string>`
- ✅ **Recipient Types**: To, Cc, Bcc (via enum `PessoasEmail`)
- ✅ **Multiple Senders**: Suporte a múltiplos remetentes
- ✅ **Email Personalization**: Personalização individual por destinatário
#### Configuration
- ✅ **appsettings.json Integration**: Configuração via Options Pattern
- ✅ **EmailServerConfiguration**: Modelo tipado para configuração SMTP
- ✅ **Dependency Injection**: Registro via `IServiceCollection`
- ✅ **Environment-based Config**: Suporte a múltiplos ambientes (Development, Production, etc.)
#### Error Handling & Logging
- ✅ **Notification Pattern**: Sistema de notificações para erros de validação
- ✅ **LogMessage Collection**: Mensagens informativas separadas de erros
- ✅ **IsValid() Method**: Verificação de validação após operações
- ✅ **Detailed Error Messages**: Mensagens descritivas com propriedade e contexto
- ✅ **DateTime Tracking**: Timestamp em cada notificação
#### Instance Management
- ✅ **ResetMailInstance()**: Limpeza de instância para reutilização em loops
- ✅ **RemoveAllAttachments()**: Limpeza de anexos
- ✅ **RemoveAllNotifications()**: Limpeza de notificações de erro
- ✅ **RemoveAllLogMessage()**: Limpeza de mensagens de log
### Technical Details
#### Target Framework
- ✅ **.NET Standard 2.1**: Compatível com .NET Core 3.0+, .NET 5+, .NET 6+, .NET 8+, .NET Framework 4.7.2+
#### Dependencies
| Package | Purpose |
| -------------------------------------------------------- | ------------------------------- |
| **MailKit** | Cliente SMTP completo e robusto |
| **Microsoft.Extensions.Options.ConfigurationExtensions** | Suporte ao Options Pattern |
| **Nuuvify.CommonPack.Email.Abstraction** | Interfaces e contratos |
#### Design Patterns
- ✅ **Repository Pattern**: Abstração via `IEmail` interface
- ✅ **Options Pattern**: Configuração via `IOptions<EmailServerConfiguration>`
- ✅ **Notification Pattern**: Rastreamento de erros e avisos
- ✅ **Fluent Interface**: Métodos encadeáveis para melhor DX
- ✅ **Dependency Injection**: Integração completa com DI container
### API Surface
#### IEmail Interface Methods
```csharp
Task<object> EnviarAsync(
Dictionary<string, string> recipients,
Dictionary<string, string> senders,
string subject,
string message,
CancellationToken cancellationToken = default)
```
```csharp
string GetEmailTemplate(
Dictionary<string, string> variables,
string templateFullName)
```
```csharp
IEmail WithAttachment(
string pathFileFullName,
EmailMidiaType midiaType,
EmailMidiaSubType midiaSubType)
```
```csharp
IEmail WithAttachment(
Stream fileStream,
EmailMidiaType midiaType,
EmailMidiaSubType midiaSubType,
string fullFileName)
```
```csharp
int CountAttachments()
bool IsValid()
IEmail RemoveAllAttachments()
IEmail RemoveAllLogMessage()
IEmail RemoveAllNotifications()
void ResetMailInstance()
```
#### Properties
```csharp
List<NotificationR> Notifications { get; set; }
List<NotificationR> LogMessage { get; set; }
EmailServerConfiguration EmailServerConfiguration { get; set; }
```
### Use Cases
#### 1. Transactional Emails
- ✅ Confirmação de cadastro
- ✅ Reset de senha
- ✅ Confirmação de pedidos
- ✅ Notificações de status
#### 2. Marketing Emails
- ✅ Newsletters
- ✅ Campanhas promocionais
- ✅ Comunicados importantes
- ✅ E-mails segmentados
#### 3. System Notifications
- ✅ Alertas de sistema
- ✅ Relatórios agendados
- ✅ Notificações de erro
- ✅ Logs de auditoria
#### 4. Bulk Emails
- ✅ Envio em lote com `ResetMailInstance()`
- ✅ Personalização individual
- ✅ Retry logic
- ✅ Error tracking
---
## Roadmap
### Version 1.1.0 - Planned
#### Enhanced Template Engine
- [ ] **Razor Template Support**: Integração com Razor Engine para templates dinâmicos
- [ ] **Template Caching**: Cache de templates compilados para melhor performance
- [ ] **Template Inheritance**: Suporte a layouts base e herança
- [ ] **Conditional Rendering**: Suporte a if/else dentro de templates
#### Advanced Features
- [ ] **Email Queue**: Sistema de fila para processamento assíncrono
- [ ] **Priority Levels**: Níveis de prioridade para envio (High, Normal, Low)
- [ ] **Scheduled Sending**: Agendamento de envios para data/hora específica
- [ ] **Bulk Send Optimization**: Otimizações para envio massivo
#### Monitoring & Telemetry
- [ ] **Send Metrics**: Métricas de envio (success rate, avg time, etc.)
- [ ] **OpenTelemetry**: Integração com OpenTelemetry para tracing
- [ ] **Health Checks**: Health check endpoint para validar SMTP
- [ ] **Event Callbacks**: Callbacks para eventos (enviado, erro, etc.)
### Version 1.2.0 - Planned
#### Provider Abstraction
- [ ] **SendGrid SDK**: Suporte nativo ao SDK SendGrid
- [ ] **AWS SES SDK**: Suporte nativo ao SDK Amazon SES
- [ ] **Azure Communication Services**: Integração com Azure
- [ ] **Provider Fallback**: Fallback automático entre provedores
#### Advanced Attachments
- [ ] **Inline Images**: Suporte a imagens embutidas no HTML
- [ ] **Cloud Attachments**: Anexar arquivos de Azure Blob, AWS S3
- [ ] **Attachment Compression**: Compressão automática de anexos grandes
- [ ] **Attachment Encryption**: Criptografia de anexos sensíveis
#### Validation & Security
- [ ] **Email Validation**: Validação avançada de e-mails (syntax, MX records)
- [ ] **Domain Verification**: Verificação de domínio (SPF, DKIM, DMARC)
- [ ] **Rate Limiting**: Limitação de taxa de envio
- [ ] **Spam Score Check**: Verificação de score de spam antes do envio
### Version 2.0.0 - Future
#### Breaking Changes
- [ ] **Async-only API**: Remover métodos síncronos (breaking change)
- [ ] **Fluent Configuration**: API fluente para configuração
- [ ] **Strong-typed Templates**: Templates tipados com compile-time checking
#### Enterprise Features
- [ ] **Multi-tenant Support**: Suporte a múltiplos tenants
- [ ] **Email Analytics**: Dashboard de analytics de e-mails
- [ ] **A/B Testing**: Testes A/B de templates e conteúdo
- [ ] **Webhook Integration**: Webhooks para eventos (aberto, clicado, bounce)
#### Performance
- [ ] **Connection Pooling**: Pool de conexões SMTP
- [ ] **Batch Processing**: Processamento em lote otimizado
- [ ] **Memory Optimization**: Otimizações de uso de memória
- [ ] **Async Streaming**: Streaming assíncrono de anexos grandes
---
## Migration Guides
### Migrating from System.Net.Mail
Se você está migrando de `System.Net.Mail` (obsoleto), aqui está como adaptar:
#### Before (System.Net.Mail)
```csharp
var mail = new MailMessage();
mail.From = new MailAddress("from@email.com");
mail.To.Add("to@email.com");
mail.Subject = "Subject";
mail.Body = "Body";
mail.IsBodyHtml = true;
var smtp = new SmtpClient("smtp.server.com", 587);
smtp.Credentials = new NetworkCredential("user", "pass");
smtp.EnableSsl = true;
smtp.Send(mail);
```
#### After (Nuuvify.CommonPack.Email)
```csharp
var recipients = new Dictionary<string, string>
{
{ "to@email.com", "Recipient Name" }
};
var senders = new Dictionary<string, string>
{
{ "from@email.com", "Sender Name" }
};
await _emailService.EnviarAsync(
recipients: recipients,
senders: senders,
subject: "Subject",
message: "Body" // HTML automático
);
```
---
## Known Issues
### Current Limitations
1. **Single SMTP Server**: Apenas um servidor SMTP por instância
- **Workaround**: Use múltiplas instâncias com diferentes configurações
2. **Template Engine**: Sistema simples de substituição de strings
- **Workaround**: Use Razor externamente ou aguarde v1.1.0
3. **No Built-in Retry**: Sem retry automático em caso de falha
- **Workaround**: Implemente retry logic manualmente (exemplo no README)
4. **Inline Images**: Sem suporte nativo a imagens inline
- **Workaround**: Use imagens hospedadas externamente ou aguarde v1.2.0
5. **No Email Tracking**: Sem tracking de abertura/clique
- **Workaround**: Use webhook provider (SendGrid, etc.) ou aguarde v2.0.0
---
## Breaking Changes
### None (Version 1.0.0)
This is the initial stable release. Future versions will document breaking changes here.
---
## Contributing
Para contribuir com o projeto:
1. Fork o repositório
2. Crie uma branch para sua feature (`git checkout -b feature/AmazingFeature`)
3. Commit suas mudanças (`git commit -m 'feat: add some amazing feature'`)
4. Push para a branch (`git push origin feature/AmazingFeature`)
5. Abra um Pull Request
### Contribution Guidelines
- Siga os padrões de código do projeto (.editorconfig)
- Escreva testes para novas funcionalidades
- Atualize a documentação (README, CHANGELOG)
- Use Conventional Commits para mensagens de commit
- Certifique-se que todos os testes passam
---
## License
Este projeto está licenciado sob a [MIT License](../../LICENSE).
---
## Support & Community
- 🐛 **Issues**: [GitHub Issues](https://github.com/nuuvify/CommonPack/issues)
- 📧 **Email**: [suporte@zocate.li](mailto:suporte@zocate.li)
- 📖 **Documentation**: [Wiki do Projeto](https://github.com/nuuvify/CommonPack/wiki)
- 💬 **Discussions**: [GitHub Discussions](https://github.com/nuuvify/CommonPack/discussions)
---
**Nuuvify CommonPack.Email** - Simplificando o envio de e-mails em .NET 📧