Como Enviar um Arquivo PDF como Anexo de Email em C#
A automatização da entrega de documentos é um requisito que surge em praticamente todas as aplicações .NET de linha de negócios. Assim que um pedido é feito, a fatura deve chegar ao cliente em questão de segundos. Quando um relatório é gerado durante a noite, as partes interessadas esperam recebê-lo em suas caixas de entrada antes de chegarem ao escritório. O formato de entrega mais simples e universalmente aceito é um PDF enviado como anexo de e-mail. Este guia descreve todo o fluxo de trabalho de ponta a ponta em C# -- gerando um documento PDF na memória com o IronPDF e, em seguida, enviando-o como anexo de e-mail usando o MailKit ou o namespace integrado System.Net.Mail, tudo sem gravar um único byte em disco.
Como instalar os pacotes necessários?
Este fluxo de trabalho é alimentado por dois pacotes: uma biblioteca para geração de PDFs e uma biblioteca para envio de e-mails. Instale ambos através do Console do Gerenciador de Pacotes no Visual Studio ou através da CLI do .NET .
Install-Package IronPdf
dotnet add package IronPdf
Install-Package MailKit
dotnet add package MailKit
Install-Package IronPdf
dotnet add package IronPdf
Install-Package MailKit
dotnet add package MailKit
O IronPDF traz um mecanismo de renderização baseado no Chromium que converte HTML, CSS e JavaScript em documentos PDF com qualidade de pixel perfeita. Ele funciona no Windows, Linux e macOS, o que significa que o mesmo código funciona em uma API Web ASP.NET Core , um serviço em segundo plano ou uma Função do Azure. MailKit é a biblioteca que a Microsoft recomenda para todo novo desenvolvimento de e-mail em .NET -- ela oferece suporte a SMTP, IMAP, POP3, OAuth 2.0 e construção completa de MIME. O código-fonte e a documentação do MailKit estão disponíveis no GitHub.
Como gerar um documento PDF na memória?
A classe ChromePdfRenderer é o ponto de entrada para a conversão de HTML para PDF . Passe uma string HTML para RenderHtmlAsPdf e você receberá de volta um objeto PdfDocument que reside inteiramente na memória. Acesse os bytes brutos através da propriedade BinaryData -- essa matriz de bytes é exatamente o que as APIs de anexos de e-mail esperam.
using IronPdf;
var renderer = new ChromePdfRenderer();
string htmlContent = """
<h1>Order Confirmation</h1>
<p>Thank you for your purchase.</p>
<table>
<tr><th>Item</th><th>Qty</th><th>Price</th></tr>
<tr><td>Widget A</td><td>2</td><td>$19.99</td></tr>
<tr><td>Widget B</td><td>1</td><td>$59.99</td></tr>
</table>
<p><strong>Order Total: $99.97</strong></p>
""";
PdfDocument pdf = renderer.RenderHtmlAsPdf(htmlContent);
// pdf.BinaryData holds the complete PDF as a byte array
byte[] pdfBytes = pdf.BinaryData;
Console.WriteLine($"PDF generated: {pdfBytes.Length} bytes");
using IronPdf;
var renderer = new ChromePdfRenderer();
string htmlContent = """
<h1>Order Confirmation</h1>
<p>Thank you for your purchase.</p>
<table>
<tr><th>Item</th><th>Qty</th><th>Price</th></tr>
<tr><td>Widget A</td><td>2</td><td>$19.99</td></tr>
<tr><td>Widget B</td><td>1</td><td>$59.99</td></tr>
</table>
<p><strong>Order Total: $99.97</strong></p>
""";
PdfDocument pdf = renderer.RenderHtmlAsPdf(htmlContent);
// pdf.BinaryData holds the complete PDF as a byte array
byte[] pdfBytes = pdf.BinaryData;
Console.WriteLine($"PDF generated: {pdfBytes.Length} bytes");
Imports IronPdf
Dim renderer As New ChromePdfRenderer()
Dim htmlContent As String = "
<h1>Order Confirmation</h1>
<p>Thank you for your purchase.</p>
<table>
<tr><th>Item</th><th>Qty</th><th>Price</th></tr>
<tr><td>Widget A</td><td>2</td><td>$19.99</td></tr>
<tr><td>Widget B</td><td>1</td><td>$59.99</td></tr>
</table>
<p><strong>Order Total: $99.97</strong></p>
"
Dim pdf As PdfDocument = renderer.RenderHtmlAsPdf(htmlContent)
' pdf.BinaryData holds the complete PDF as a byte array
Dim pdfBytes As Byte() = pdf.BinaryData
Console.WriteLine($"PDF generated: {pdfBytes.Length} bytes")
O método RenderHtmlAsPdf analisa o HTML usando o mesmo mecanismo Chromium que alimenta o Google Chrome, portanto, tabelas, CSS Grid, Flexbox e fontes incorporadas são renderizadas exatamente como em um navegador. O resultado é um PdfDocument cuja propriedade BinaryData retorna o binário PDF completo sem nenhuma leitura ou gravação em disco. Para documentos que incluem imagens ou folhas de estilo externas, use o parâmetro opcional BasePath para indicar ao IronPDF onde resolver URLs de recursos relativos -- isso é abordado em detalhes na página de instruções sobre como converter arquivos HTML em PDF .
Configurar o layout da página e cabeçalhos personalizados
Antes de anexar o PDF, você pode configurar as margens, cabeçalhos ou rodapés. Todas as opções de layout estão disponíveis na propriedade RenderingOptions:
using IronPdf;
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.MarginTop = 15;
renderer.RenderingOptions.MarginBottom = 15;
renderer.RenderingOptions.MarginLeft = 12;
renderer.RenderingOptions.MarginRight = 12;
renderer.RenderingOptions.HtmlHeader = new HtmlHeaderFooter
{
HtmlFragment = "<div style='font-size:9pt;color:#666;text-align:right;'>Monthly Report</div>",
DrawDividerLine = true
};
renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
{
HtmlFragment = "<div style='font-size:8pt;text-align:center;'>{page} of {total-pages}</div>"
};
PdfDocument pdf = renderer.RenderHtmlAsPdf("<h1>Monthly Summary</h1><p>See attached data.</p>");
byte[] pdfBytes = pdf.BinaryData;
using IronPdf;
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.MarginTop = 15;
renderer.RenderingOptions.MarginBottom = 15;
renderer.RenderingOptions.MarginLeft = 12;
renderer.RenderingOptions.MarginRight = 12;
renderer.RenderingOptions.HtmlHeader = new HtmlHeaderFooter
{
HtmlFragment = "<div style='font-size:9pt;color:#666;text-align:right;'>Monthly Report</div>",
DrawDividerLine = true
};
renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
{
HtmlFragment = "<div style='font-size:8pt;text-align:center;'>{page} of {total-pages}</div>"
};
PdfDocument pdf = renderer.RenderHtmlAsPdf("<h1>Monthly Summary</h1><p>See attached data.</p>");
byte[] pdfBytes = pdf.BinaryData;
Imports IronPdf
Dim renderer As New ChromePdfRenderer()
renderer.RenderingOptions.MarginTop = 15
renderer.RenderingOptions.MarginBottom = 15
renderer.RenderingOptions.MarginLeft = 12
renderer.RenderingOptions.MarginRight = 12
renderer.RenderingOptions.HtmlHeader = New HtmlHeaderFooter With {
.HtmlFragment = "<div style='font-size:9pt;color:#666;text-align:right;'>Monthly Report</div>",
.DrawDividerLine = True
}
renderer.RenderingOptions.HtmlFooter = New HtmlHeaderFooter With {
.HtmlFragment = "<div style='font-size:8pt;text-align:center;'>{page} of {total-pages}</div>"
}
Dim pdf As PdfDocument = renderer.RenderHtmlAsPdf("<h1>Monthly Summary</h1><p>See attached data.</p>")
Dim pdfBytes As Byte() = pdf.BinaryData
As margens estão em milímetros. Os tokens {page} e {total-pages} são substituídos no momento da renderização. A página de instruções para converter string HTML em PDF aborda o conjunto completo de opções de renderização. Você também pode adicionar marcas d'água ou carimbos de texto e imagens ao documento gerado antes de anexá-lo.
Como anexar um PDF a um e-mail com o MailKit?
O MailKit constrói uma árvore de mensagens MIME diretamente, dando a você controle total sobre o tipo de conteúdo, a codificação e os metadados dos anexos. A classe auxiliar BodyBuilder simplifica o caso comum de um corpo de texto ou HTML com um ou mais anexos de arquivo.
using IronPdf;
using MailKit.Net.Smtp;
using MailKit.Security;
using MimeKit;
// Step 1 -- generate the PDF in memory
var renderer = new ChromePdfRenderer();
PdfDocument pdf = renderer.RenderHtmlAsPdf("<h1>Monthly Report</h1><p>Generated automatically.</p>");
// Step 2 -- build the email message
var message = new MimeMessage();
message.From.Add(new MailboxAddress("Reports Service", "reports@example.com"));
message.To.Add(new MailboxAddress("Alice Smith", "alice@example.com"));
message.Subject = "Your Monthly Report is Ready";
var builder = new BodyBuilder();
builder.TextBody = "Hello Alice,\n\nPlease find your monthly report attached.\n\nRegards,\nReports Service";
builder.HtmlBody = "<p>Hello Alice,</p><p>Please find your monthly report attached.</p>";
// Add the in-memory PDF as an attachment
builder.Attachments.Add("MonthlyReport.pdf", pdf.BinaryData, new ContentType("application", "pdf"));
message.Body = builder.ToMessageBody();
// Step 3 -- send via SMTP with TLS
using var client = new SmtpClient();
await client.ConnectAsync("smtp.example.com", 587, SecureSocketOptions.StartTls);
await client.AuthenticateAsync("username", "app-password");
await client.SendAsync(message);
await client.DisconnectAsync(true);
using IronPdf;
using MailKit.Net.Smtp;
using MailKit.Security;
using MimeKit;
// Step 1 -- generate the PDF in memory
var renderer = new ChromePdfRenderer();
PdfDocument pdf = renderer.RenderHtmlAsPdf("<h1>Monthly Report</h1><p>Generated automatically.</p>");
// Step 2 -- build the email message
var message = new MimeMessage();
message.From.Add(new MailboxAddress("Reports Service", "reports@example.com"));
message.To.Add(new MailboxAddress("Alice Smith", "alice@example.com"));
message.Subject = "Your Monthly Report is Ready";
var builder = new BodyBuilder();
builder.TextBody = "Hello Alice,\n\nPlease find your monthly report attached.\n\nRegards,\nReports Service";
builder.HtmlBody = "<p>Hello Alice,</p><p>Please find your monthly report attached.</p>";
// Add the in-memory PDF as an attachment
builder.Attachments.Add("MonthlyReport.pdf", pdf.BinaryData, new ContentType("application", "pdf"));
message.Body = builder.ToMessageBody();
// Step 3 -- send via SMTP with TLS
using var client = new SmtpClient();
await client.ConnectAsync("smtp.example.com", 587, SecureSocketOptions.StartTls);
await client.AuthenticateAsync("username", "app-password");
await client.SendAsync(message);
await client.DisconnectAsync(true);
Imports IronPdf
Imports MailKit.Net.Smtp
Imports MailKit.Security
Imports MimeKit
' Step 1 -- generate the PDF in memory
Dim renderer As New ChromePdfRenderer()
Dim pdf As PdfDocument = renderer.RenderHtmlAsPdf("<h1>Monthly Report</h1><p>Generated automatically.</p>")
' Step 2 -- build the email message
Dim message As New MimeMessage()
message.From.Add(New MailboxAddress("Reports Service", "reports@example.com"))
message.To.Add(New MailboxAddress("Alice Smith", "alice@example.com"))
message.Subject = "Your Monthly Report is Ready"
Dim builder As New BodyBuilder()
builder.TextBody = "Hello Alice," & vbCrLf & vbCrLf & "Please find your monthly report attached." & vbCrLf & vbCrLf & "Regards," & vbCrLf & "Reports Service"
builder.HtmlBody = "<p>Hello Alice,</p><p>Please find your monthly report attached.</p>"
' Add the in-memory PDF as an attachment
builder.Attachments.Add("MonthlyReport.pdf", pdf.BinaryData, New ContentType("application", "pdf"))
message.Body = builder.ToMessageBody()
' Step 3 -- send via SMTP with TLS
Using client As New SmtpClient()
Await client.ConnectAsync("smtp.example.com", 587, SecureSocketOptions.StartTls)
Await client.AuthenticateAsync("username", "app-password")
Await client.SendAsync(message)
Await client.DisconnectAsync(True)
End Using
builder.Attachments.Add aceita três argumentos: o nome do arquivo que o destinatário vê em seu cliente de e-mail, a matriz de bytes bruta de pdf.BinaryData e uma instância de ContentType especificando o tipo MIME como application/pdf. Os métodos SMTP assíncronos mantêm a thread de chamada livre enquanto a operação de rede é concluída — algo crucial em controladores ASP.NET Core que lidam com dezenas de solicitações simultâneas.
SecureSocketOptions.StartTls negocia um canal criptografado com o servidor SMTP na porta 587. Para o Gmail, use uma Senha de Aplicativo em vez da senha da sua conta: gere uma em Segurança da Conta do Google > Senhas de Aplicativos e, em seguida, passe-a para AuthenticateAsync. Para o Microsoft 365, configure a autenticação OAuth 2.0 por meio da classe SaslMechanismOAuth2 do MailKit se o seu locatário tiver desativado a autenticação básica.
Envio para vários destinatários
Para copiar várias pessoas no mesmo e-mail, adicione os endereços às coleções To, Cc ou Bcc antes de chamar SendAsync:
message.To.Add(new MailboxAddress("Alice Smith", "alice@example.com"));
message.To.Add(new MailboxAddress("Bob Jones", "bob@example.com"));
message.Cc.Add(new MailboxAddress("Carol Manager", "carol@example.com"));
message.To.Add(new MailboxAddress("Alice Smith", "alice@example.com"));
message.To.Add(new MailboxAddress("Bob Jones", "bob@example.com"));
message.Cc.Add(new MailboxAddress("Carol Manager", "carol@example.com"));
message.To.Add(New MailboxAddress("Alice Smith", "alice@example.com"))
message.To.Add(New MailboxAddress("Bob Jones", "bob@example.com"))
message.Cc.Add(New MailboxAddress("Carol Manager", "carol@example.com"))
Uma única chamada SendAsync entrega a mensagem a todos os endereços. O MailKit agrupa os comandos RCPT TO em uma única sessão SMTP, portanto não há perda de desempenho para vários destinatários.
Como usar o .NET como alternativa?
Para projetos direcionados a versões mais antigas do .NET ou projetos onde a adição de um pacote NuGet de terceiros não é permitida, o namespace integrado System.Net.Mail lida com a entrega SMTP básica. A Microsoft já não o recomenda para novos desenvolvimentos, mas abrange os casos de uso comuns sem dependências adicionais.
using IronPdf;
using System.Net;
using System.Net.Mail;
// Generate the PDF
var renderer = new ChromePdfRenderer();
PdfDocument pdf = renderer.RenderHtmlAsPdf("<h1>Invoice #1001</h1><p>Amount due: $350.00</p>");
// Build the mail message
using var message = new MailMessage("invoices@example.com", "customer@example.com");
message.Subject = "Invoice #1001 Attached";
message.Body = "Your invoice is attached to this email. Please remit payment within 30 days.";
message.IsBodyHtml = false;
// Wrap the byte array in a MemoryStream for the Attachment constructor
var stream = new MemoryStream(pdf.BinaryData);
message.Attachments.Add(new Attachment(stream, "Invoice-1001.pdf", "application/pdf"));
// Send via SMTP
using var client = new SmtpClient("smtp.example.com", 587)
{
Credentials = new NetworkCredential("username", "password"),
EnableSsl = true
};
await client.SendMailAsync(message);
using IronPdf;
using System.Net;
using System.Net.Mail;
// Generate the PDF
var renderer = new ChromePdfRenderer();
PdfDocument pdf = renderer.RenderHtmlAsPdf("<h1>Invoice #1001</h1><p>Amount due: $350.00</p>");
// Build the mail message
using var message = new MailMessage("invoices@example.com", "customer@example.com");
message.Subject = "Invoice #1001 Attached";
message.Body = "Your invoice is attached to this email. Please remit payment within 30 days.";
message.IsBodyHtml = false;
// Wrap the byte array in a MemoryStream for the Attachment constructor
var stream = new MemoryStream(pdf.BinaryData);
message.Attachments.Add(new Attachment(stream, "Invoice-1001.pdf", "application/pdf"));
// Send via SMTP
using var client = new SmtpClient("smtp.example.com", 587)
{
Credentials = new NetworkCredential("username", "password"),
EnableSsl = true
};
await client.SendMailAsync(message);
Imports IronPdf
Imports System.Net
Imports System.Net.Mail
Imports System.IO
' Generate the PDF
Dim renderer As New ChromePdfRenderer()
Dim pdf As PdfDocument = renderer.RenderHtmlAsPdf("<h1>Invoice #1001</h1><p>Amount due: $350.00</p>")
' Build the mail message
Using message As New MailMessage("invoices@example.com", "customer@example.com")
message.Subject = "Invoice #1001 Attached"
message.Body = "Your invoice is attached to this email. Please remit payment within 30 days."
message.IsBodyHtml = False
' Wrap the byte array in a MemoryStream for the Attachment constructor
Dim stream As New MemoryStream(pdf.BinaryData)
message.Attachments.Add(New Attachment(stream, "Invoice-1001.pdf", "application/pdf"))
' Send via SMTP
Using client As New SmtpClient("smtp.example.com", 587)
client.Credentials = New NetworkCredential("username", "password")
client.EnableSsl = True
Await client.SendMailAsync(message)
End Using
End Using
A principal diferença em comparação com o MailKit é que System.Net.Mail.Attachment não aceita um array de bytes diretamente -- você deve envolver pdf.BinaryData em um MemoryStream primeiro. Tanto o MailMessage quanto o SmtpClient são envolvidos em instruções using, que descartam a conexão SMTP e liberam o fluxo subjacente após o envio. Se você omitir o using em MailMessage, o fluxo de anexos poderá ser descartado antes da conclusão do envio em alguns tempos de execução.
Escolhendo entre MailKit e .NET
| Recurso | MailKit | System.Net.Mail |
|---|---|---|
| Autenticação OAuth 2.0 | Sim | Não |
| Suporte a IMAP/POP3 | Sim | Não |
| API assíncrona em primeiro lugar | Sim | Parcial |
| Recomendação da Microsoft | Recomendado | Legado |
| Pacote NuGet adicional | Obrigatório | Não é necessário |
| Construção MIME complexa | Apoio total | Básico |
Escolha o MailKit para qualquer novo projeto, especialmente se o servidor SMTP exigir OAuth ou se você precisar de IMAP para ler as respostas. Use System.Net.Mail quando a base de código já depender dele e o custo da migração não for justificado.
Como você aplica esse padrão a fluxos de trabalho empresariais reais?
O padrão de conversão de PDF para e-mail em memória aplica-se diretamente aos cenários de automação de documentos que impulsionam a maioria das aplicações empresariais.
Automação de Faturas
Um sistema de gerenciamento de pedidos de comércio eletrônico gera uma fatura em PDF imediatamente após a captura do pagamento. O evento OrderConfirmed aciona um método que chama RenderHtmlAsPdf com uma string HTML gerada por um modelo Razor, preenchida com dados do pedido, e então envia o resultado para o endereço de e-mail do cliente. Como o PDF nunca acessa o sistema de arquivos, não há arquivos residuais para limpar, nem condições de corrida em um diretório temporário compartilhado, nem problemas de permissão em implantações em contêineres. Para obter mais informações sobre como renderizar HTML a partir de views Razor , consulte o guia de geração de PDF do ASP.NET Core .
Distribuição programada de relatórios
Um serviço em segundo plano agendado com IHostedService gera um resumo analítico semanal às 06:00 de todas as segundas-feiras. O processo consulta o banco de dados, gera uma string de relatório HTML, renderiza-a com o IronPDF e usa o MailKit para enviá-la a uma lista de distribuição. Todo o pipeline é executado como um fluxo de trabalho assíncrono, portanto, não mantém uma thread alocada no pool de threads durante o handshake SMTP. Para cargas de trabalho hospedadas no Azure, o guia do gerador de PDF do Azure explica como implantar o IronPDF no Azure App Service e no Azure Functions.
Geração de recibos no ASP.NET Core
Em uma API mínima ou ação de controlador do ASP.NET Core , um endpoint POST recebe uma carga útil de finalização de compra, gera um PDF do recibo e retorna um HTTP 200 enquanto simultaneamente envia o e-mail. Mantenha a lógica de envio de e-mail em segundo plano Task para que a resposta HTTP retorne imediatamente ao cliente:
app.MapPost("/checkout", async (CheckoutRequest req, IEmailService emailService) =>
{
var renderer = new ChromePdfRenderer();
PdfDocument receipt = renderer.RenderHtmlAsPdf(BuildReceiptHtml(req));
// Fire and forget -- do not await so the HTTP response is immediate
_ = emailService.SendReceiptAsync(req.CustomerEmail, receipt.BinaryData);
return Results.Ok(new { message = "Order confirmed." });
});
app.MapPost("/checkout", async (CheckoutRequest req, IEmailService emailService) =>
{
var renderer = new ChromePdfRenderer();
PdfDocument receipt = renderer.RenderHtmlAsPdf(BuildReceiptHtml(req));
// Fire and forget -- do not await so the HTTP response is immediate
_ = emailService.SendReceiptAsync(req.CustomerEmail, receipt.BinaryData);
return Results.Ok(new { message = "Order confirmed." });
});
Imports System.Threading.Tasks
app.MapPost("/checkout", Async Function(req As CheckoutRequest, emailService As IEmailService) As Task(Of IResult)
Dim renderer As New ChromePdfRenderer()
Dim receipt As PdfDocument = renderer.RenderHtmlAsPdf(BuildReceiptHtml(req))
' Fire and forget -- do not await so the HTTP response is immediate
_ = emailService.SendReceiptAsync(req.CustomerEmail, receipt.BinaryData)
Return Results.Ok(New With {.message = "Order confirmed."})
End Function)
Isso mantém o tempo de resposta da API abaixo de 100 ms, mesmo quando o servidor SMTP está lento. O emailService está registrado como um serviço com escopo ou transitório que encapsula o MailKit SmtpClient.
Como você lida com erros e novas tentativas?
As operações de rede falham. Os servidores SMTP estão temporariamente indisponíveis, os tokens de autenticação expiram e os limites de tamanho dos anexos variam conforme o provedor. Incorpore resiliência ao processo de envio de e-mails desde o início.
Envolva a lógica de envio do MailKit em um bloco try/catch e registre as falhas em uma fila persistente para que possam ser repetidas:
using IronPdf;
using MailKit.Net.Smtp;
using MailKit.Security;
using MimeKit;
using Microsoft.Extensions.Logging;
async Task SendPdfEmailWithRetryAsync(
byte[] pdfBytes,
string recipientEmail,
string subject,
ILogger logger,
int maxAttempts = 3)
{
for (int attempt = 1; attempt <= maxAttempts; attempt++)
{
try
{
var message = new MimeMessage();
message.From.Add(new MailboxAddress("Mailer", "mailer@example.com"));
message.To.Add(MailboxAddress.Parse(recipientEmail));
message.Subject = subject;
var builder = new BodyBuilder { TextBody = "Your document is attached." };
builder.Attachments.Add("document.pdf", pdfBytes, new ContentType("application", "pdf"));
message.Body = builder.ToMessageBody();
using var smtpClient = new SmtpClient();
await smtpClient.ConnectAsync("smtp.example.com", 587, SecureSocketOptions.StartTls);
await smtpClient.AuthenticateAsync("user", "pass");
await smtpClient.SendAsync(message);
await smtpClient.DisconnectAsync(true);
logger.LogInformation("Email sent to {Email} on attempt {Attempt}", recipientEmail, attempt);
return;
}
catch (Exception ex) when (attempt < maxAttempts)
{
logger.LogWarning(ex, "Send attempt {Attempt} failed. Retrying...", attempt);
await Task.Delay(TimeSpan.FromSeconds(Math.Pow(2, attempt)));
}
}
}
using IronPdf;
using MailKit.Net.Smtp;
using MailKit.Security;
using MimeKit;
using Microsoft.Extensions.Logging;
async Task SendPdfEmailWithRetryAsync(
byte[] pdfBytes,
string recipientEmail,
string subject,
ILogger logger,
int maxAttempts = 3)
{
for (int attempt = 1; attempt <= maxAttempts; attempt++)
{
try
{
var message = new MimeMessage();
message.From.Add(new MailboxAddress("Mailer", "mailer@example.com"));
message.To.Add(MailboxAddress.Parse(recipientEmail));
message.Subject = subject;
var builder = new BodyBuilder { TextBody = "Your document is attached." };
builder.Attachments.Add("document.pdf", pdfBytes, new ContentType("application", "pdf"));
message.Body = builder.ToMessageBody();
using var smtpClient = new SmtpClient();
await smtpClient.ConnectAsync("smtp.example.com", 587, SecureSocketOptions.StartTls);
await smtpClient.AuthenticateAsync("user", "pass");
await smtpClient.SendAsync(message);
await smtpClient.DisconnectAsync(true);
logger.LogInformation("Email sent to {Email} on attempt {Attempt}", recipientEmail, attempt);
return;
}
catch (Exception ex) when (attempt < maxAttempts)
{
logger.LogWarning(ex, "Send attempt {Attempt} failed. Retrying...", attempt);
await Task.Delay(TimeSpan.FromSeconds(Math.Pow(2, attempt)));
}
}
}
Imports IronPdf
Imports MailKit.Net.Smtp
Imports MailKit.Security
Imports MimeKit
Imports Microsoft.Extensions.Logging
Public Async Function SendPdfEmailWithRetryAsync(
pdfBytes As Byte(),
recipientEmail As String,
subject As String,
logger As ILogger,
Optional maxAttempts As Integer = 3) As Task
For attempt As Integer = 1 To maxAttempts
Try
Dim message = New MimeMessage()
message.From.Add(New MailboxAddress("Mailer", "mailer@example.com"))
message.To.Add(MailboxAddress.Parse(recipientEmail))
message.Subject = subject
Dim builder = New BodyBuilder With {
.TextBody = "Your document is attached."
}
builder.Attachments.Add("document.pdf", pdfBytes, New ContentType("application", "pdf"))
message.Body = builder.ToMessageBody()
Using smtpClient = New SmtpClient()
Await smtpClient.ConnectAsync("smtp.example.com", 587, SecureSocketOptions.StartTls)
Await smtpClient.AuthenticateAsync("user", "pass")
Await smtpClient.SendAsync(message)
Await smtpClient.DisconnectAsync(True)
End Using
logger.LogInformation("Email sent to {Email} on attempt {Attempt}", recipientEmail, attempt)
Return
Catch ex As Exception When attempt < maxAttempts
logger.LogWarning(ex, "Send attempt {Attempt} failed. Retrying...", attempt)
Await Task.Delay(TimeSpan.FromSeconds(Math.Pow(2, attempt)))
End Try
Next
End Function
O recuo exponencial — 2 segundos após a primeira falha, 4 após a segunda — evita sobrecarregar um servidor SMTP já saturado. Em aplicações de produção, substitua o loop de repetição por uma fila de mensagens (Azure Service Bus, RabbitMQ ou AWS SQS) para que as falhas persistam mesmo após reinicializações da aplicação.
O IronPDF também gera um erro PdfException se o conteúdo HTML não puder ser renderizado. Capture-o separadamente das exceções SMTP para que a mensagem de erro seja específica:
PdfDocument pdf;
try
{
pdf = renderer.RenderHtmlAsPdf(htmlContent);
}
catch (IronPdf.Exceptions.PdfException ex)
{
logger.LogError(ex, "PDF rendering failed");
throw;
}
PdfDocument pdf;
try
{
pdf = renderer.RenderHtmlAsPdf(htmlContent);
}
catch (IronPdf.Exceptions.PdfException ex)
{
logger.LogError(ex, "PDF rendering failed");
throw;
}
Imports IronPdf.Exceptions
Dim pdf As PdfDocument
Try
pdf = renderer.RenderHtmlAsPdf(htmlContent)
Catch ex As PdfException
logger.LogError(ex, "PDF rendering failed")
Throw
End Try
Separar os erros de renderização dos erros de entrega torna a depuração mais rápida. Para uma visão mais abrangente sobre o tratamento de erros em fluxos de trabalho automatizados de documentos, o guia de geração de PDF em 5 etapas aborda os padrões de validação em detalhes.
Como manter o tamanho do anexo dentro dos limites do provedor?
A maioria dos provedores de e-mail comerciais impõe um tamanho máximo para anexos. O Gmail limita anexos individuais a 25 MB; O Microsoft 365 define, por padrão, 20 MB para caixas de correio padrão. Um relatório HTML com formatação complexa e imagens incorporadas pode exceder esses limites inesperadamente.
Três técnicas ajudam a manter-se dentro dos limites:
Comprima as imagens antes de renderizá-las. Imagens embutidas devem usar JPEG ou WebP comprimidos em vez de PNG não comprimido. Um logotipo PNG de 600 dpi pode adicionar vários megabytes ao PDF; Uma imagem JPEG com 85% de qualidade normalmente tem menos de 200 KB para o mesmo resultado visual.
Use as configurações de compressão do IronPDF. O método PdfDocument.CompressImages reduz a resolução dos bitmaps incorporados após a renderização. Ligue antes de ler BinaryData:
pdf.CompressImages(60); // quality 0-100
byte[] compressedPdfBytes = pdf.BinaryData;
pdf.CompressImages(60); // quality 0-100
byte[] compressedPdfBytes = pdf.BinaryData;
pdf.CompressImages(60) ' quality 0-100
Dim compressedPdfBytes As Byte() = pdf.BinaryData
Divida relatórios grandes em vários e-mails. Se um relatório exceder o limite do provedor mesmo após a compressão, gere um PDF por seção e envie cada um em um e-mail separado. A página de instruções sobre como dividir e mesclar PDFs mostra como dividir um PdfDocument por intervalo de páginas usando CopyPages.
Referências externas para limites de tamanho de SMTP: limites de anexos do Gmail , limites de tamanho de mensagens do Microsoft 365 .
Quais são os seus próximos passos?
Agora você tem um modelo funcional para gerar um PDF na memória com o IronPDF e enviá-lo como anexo de e-mail usando o MailKit ou o System.Net.Mail. A abordagem em memória elimina leituras e gravações em disco, simplifica implantações em contêineres e escala para cenários de alto desempenho sem exigir limpeza temporária de arquivos.
Para aprofundar a integração:
Leia o tutorial de HTML para PDF para dominar layouts de documentos complexos com cabeçalhos, rodapés e numeração de páginas.
- Explore as opções de renderização de PDF personalizadas para controlar margens, tamanho da página e tempo limite de execução do JavaScript .
- Adicione uma assinatura digital ao PDF gerado antes de anexá-lo, fornecendo aos destinatários documentos invioláveis.
- Implante no Azure Functions ou no Serviço de Aplicativos para geração de documentos sem servidor em escala. Experimente o IronPDF gratuitamente para testar todos os recursos antes de adquirir uma licença de produção ou consulte as opções de licenciamento para obter informações sobre preços de implementação.
Perguntas frequentes
Como posso enviar um PDF gerado como anexo de e-mail em C#?
Usando o IronPDF, você pode enviar arquivos PDF gerados como anexos de email, integrando suas capacidades de criação de PDF com os recursos de envio de email do .NET.
Quais são os benefícios de enviar arquivos PDF por e-mail em aplicações .NET?
O envio de arquivos PDF por e-mail em aplicativos .NET ajuda a automatizar a entrega de documentos, otimizando os fluxos de trabalho empresariais e aprimorando a comunicação com o cliente.
O IronPDF consegue lidar com conteúdo dinâmico em PDFs anexados a e-mails?
Sim, o IronPDF gera dinamicamente conteúdo PDF, tornando-o adequado para aplicações baseadas em eventos que requerem o envio de PDFs personalizados como anexos de email.
Quais parâmetros são comumente usados nos métodos de envio de e-mail com o IronPDF?
Os parâmetros comuns incluem o assunto do e-mail, as informações do remetente e os EventArgs, que garantem um processamento eficiente em aplicações orientadas a eventos.
Por que o IronPDF é adequado para automatizar a entrega de documentos?
O IronPDF é adequado para automatizar a entrega de documentos porque fornece criação de PDF confiável e se integra com as capacidades de envio de email do C#.
É possível agendar o envio de PDFs por e-mail com o IronPDF?
Sim, o IronPDF pode ser integrado a tarefas agendadas para automatizar o envio de e-mails em PDF em horários específicos, melhorando a eficiência do fluxo de trabalho.
O IronPDF permite a criação de PDFs a partir de diversas fontes de dados para anexos de e-mail?
O IronPDF suporta a criação de PDFs a partir de múltiplas fontes de dados, permitindo que desenvolvedores gerem documentos detalhados para anexos de email.
Como o IronPDF aprimora a comunicação por e-mail com os clientes?
Ao permitir a geração e o envio de documentos PDF detalhados como anexos, o IronPDF aprimora o profissionalismo e a clareza da comunicação por e-mail com os clientes.
O IronPDF pode ser usado para enviar faturas e relatórios como anexos em PDF?
Sim, o IronPDF é bem adequado para gerar e enviar faturas, relatórios e outros documentos como anexos em PDF, atendendo a diversas necessidades empresariais.
Qual o papel do IronPDF na melhoria dos fluxos de trabalho empresariais?
O IronPDF melhora os fluxos de trabalho empresariais ao permitir a criação e distribuição de documentos PDF, reduzindo a intervenção manual e erros.


