Cómo enviar un archivo PDF como un adjunto de correo electrónico en C#
La automatización de la entrega de documentos es un requisito que surge en casi todas las aplicaciones .NET de líneas de negocio. Cuando se realiza un pedido, la factura debe llegar al cliente en cuestión de segundos. Cuando un informe se procesa durante la noche, las partes interesadas esperan recibirlo en su bandeja de entrada antes de llegar a la oficina. El formato de entrega más sencillo y universal es un PDF que se envía como archivo adjunto en un correo electrónico. Esta guía lo guiará a través del flujo de trabajo completo de extremo a extremo en C#: generar un documento PDF en la memoria con IronPDF y luego enviarlo como un archivo adjunto de correo electrónico usando MailKit o el espacio de nombres System.Net.Mail integrado, todo sin escribir un solo byte en el disco.
¿Cómo instalar los paquetes necesarios?
Dos paquetes impulsan este flujo de trabajo: una biblioteca de generación de PDF y una biblioteca de envío de correo electrónico. Instálelos ambos a través de la Consola del Administrador de paquetes en Visual Studio o mediante la CLI de .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
IronPDF ofrece un motor de renderizado basado en Chromium que convierte HTML, CSS y JavaScript en documentos PDF con píxeles perfectos. Se ejecuta en Windows, Linux y macOS, lo que significa que el mismo código funciona en una API web ASP.NET Core , un servicio en segundo plano o una función de Azure. MailKit es la biblioteca que Microsoft recomienda para todo el nuevo desarrollo de correo electrónico .NET : admite SMTP, IMAP, POP3, OAuth 2.0 y construcción MIME completa. El código fuente y la documentación de MailKit están disponibles en GitHub.
¿Cómo se genera un documento PDF en la memoria?
La clase ChromePdfRenderer es el punto de entrada para la conversión de HTML a PDF . Pase una cadena HTML a RenderHtmlAsPdf y obtendrá un objeto PdfDocument que reside completamente en la memoria. Acceda a los bytes sin procesar a través de la propiedad BinaryData: esta matriz de bytes es exactamente lo que esperan las API de archivos adjuntos de correo electrónico.
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")
El método RenderHtmlAsPdf analiza el HTML utilizando el mismo motor Chromium que impulsa Google Chrome, por lo que las tablas, CSS Grid, Flexbox y las fuentes integradas se representan exactamente como lo hacen en un navegador. El resultado es un PdfDocument cuya propiedad BinaryData devuelve el binario PDF completo sin ninguna lectura ni escritura en el disco. Para los documentos que incorporan imágenes externas u hojas de estilo, use el parámetro opcional BasePath para indicar a IronPDF dónde resolver las URL de recursos relativos: esto se explica en detalle en la página de instrucciones para convertir un archivo HTML a PDF .
Configuración del diseño de página y encabezados personalizados
Antes de adjuntar el PDF, es posible que desee configurar márgenes, encabezados o pies de página. Todas las opciones de diseño se encuentran en la propiedad 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
Los márgenes están en milímetros. Los tokens {page} y {total-pages} se reemplazan durante el renderizado. La página de instrucciones para convertir cadenas HTML en PDF abarca todas las opciones de renderizado. También puede agregar marcas de agua o sellar texto e imágenes en el documento generado antes de adjuntarlo.
¿Cómo adjuntar un PDF a un correo electrónico con MailKit?
MailKit crea un árbol de mensajes MIME directamente, lo que le brinda control total sobre el tipo de contenido, la codificación y los metadatos de los archivos adjuntos. La clase auxiliar BodyBuilder simplifica el caso común de un cuerpo de texto o HTML con uno o más archivos adjuntos.
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 acepta tres argumentos: el nombre de archivo que el destinatario ve en su cliente de correo electrónico, la matriz de bytes sin procesar de pdf.BinaryData y una instancia de ContentType que especifica el tipo MIME como application/pdf. Los métodos SMTP asíncronos mantienen libre el hilo de llamada mientras se completa la operación de red, lo que resulta fundamental en los controladores ASP.NET Core que manejan docenas de solicitudes simultáneas.
SecureSocketOptions.StartTls negocia un canal cifrado con el servidor SMTP en el puerto 587. Para Gmail, use una contraseña de aplicación en lugar de la contraseña de su cuenta: genere una en Seguridad de la cuenta de Google > Contraseñas de aplicaciones y luego pásela a AuthenticateAsync. Para Microsoft 365, configure la autenticación OAuth 2.0 a través de la clase SaslMechanismOAuth2 de MailKit si su inquilino ha deshabilitado la autenticación básica.
Envío a múltiples destinatarios
Para copiar a varias personas en el mismo correo electrónico, agregue direcciones a las colecciones To, Cc o Bcc antes de llamar a 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"))
Una sola llamada SendAsync envía el mensaje a todas las direcciones. MailKit agrupa los comandos RCPT TO en una sesión SMTP, por lo que no hay ninguna penalización en el rendimiento para múltiples destinatarios.
¿Cómo utilizar System .NET.Mail como alternativa?
Para proyectos dirigidos a versiones anteriores de .NET o proyectos en los que no se permite agregar un paquete NuGet de terceros, el espacio de nombres System.Net.Mail integrado maneja la entrega SMTP básica. Microsoft ya no lo recomienda para nuevos desarrollos, pero cubre los casos de uso comunes sin dependencias adicionales.
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
La principal diferencia con MailKit radica en que System.Net.Mail.Attachment no acepta una matriz de bytes directamente; primero debe incluir pdf.BinaryData en un MemoryStream. Tanto MailMessage como SmtpClient se incluyen en las instrucciones using, que eliminan la conexión SMTP y vacían el flujo subyacente tras el envío. Si omite using en MailMessage, el flujo de archivos adjuntos puede eliminarse antes de que se complete el envío en algunos tiempos de ejecución.
Elegir entre MailKit y System .NET.Mail
| Función | MailKit | System.Net.Mail |
|---|---|---|
| Autenticación OAuth 2.0 | Sí | No |
| Compatibilidad con IMAP/POP3 | Sí | No |
| API asíncrona | Sí | Parcial |
| Recomendación de Microsoft | Recomendado | Legado |
| Paquete NuGet adicional | Requerido | No requerido |
| Construcción MIME compleja | Soporte completo | Básico |
Elija MailKit para cualquier proyecto nuevo, especialmente si el servidor SMTP requiere OAuth o si necesita IMAP para leer las respuestas. Utilice System.Net.Mail cuando el código base ya depende de él y el costo de la migración no está justificado.
¿Cómo se aplica este patrón a los flujos de trabajo empresariales reales?
El patrón de PDF a correo electrónico en memoria se aplica directamente a los escenarios de automatización de documentos que impulsan la mayoría de las aplicaciones comerciales.
Automatización de facturas
Un gestor de pedidos de comercio electrónico genera una factura en PDF inmediatamente después de que se captura el pago. El evento OrderConfirmed activa un método que llama a RenderHtmlAsPdf con una cadena HTML con plantilla Razor rellena a partir de datos del pedido y luego envía el resultado a la dirección de correo electrónico del cliente. Como el PDF nunca toca el sistema de archivos, no hay archivos sobrantes para limpiar, no hay condiciones de carrera en un directorio temporal compartido y no hay problemas de permisos en implementaciones en contenedores. Para obtener más información sobre la representación de HTML desde las vistas de Razor , consulte la guía de generación de PDF de ASP.NET Core .
Distribución programada de informes
Un servicio en segundo plano programado con IHostedService genera un resumen analítico semanal a las 06:00 todos los lunes. Consulta la base de datos, crea una cadena de informe HTML, la renderiza con IronPDF y usa MailKit para enviarla a una lista de distribución. Toda la canalización se ejecuta como un flujo de trabajo asíncrono, por lo que no mantiene un subproceso del grupo de subprocesos durante el protocolo de enlace SMTP. Para las cargas de trabajo alojadas en Azure, la guía del generador de PDF de Azure explica cómo implementar IronPDF dentro de Azure App Service y Azure Functions.
Generación de recibos en ASP.NET Core
En una acción de controlador o API mínima de ASP.NET Core , un punto final POST recibe una carga útil de pago, genera un PDF de recibo y devuelve un HTTP 200 mientras envía simultáneamente el correo electrónico. Mantenga la lógica de envío de correo electrónico en segundo plano Task para que la respuesta HTTP regrese al cliente inmediatamente:
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)
Esto mantiene el tiempo de respuesta de la API por debajo de 100 ms incluso cuando el servidor SMTP es lento. El emailService está registrado como un servicio transitorio o de alcance que envuelve el MailKit SmtpClient.
¿Cómo manejar errores y reintentos?
Las operaciones de red fallan. Los servidores SMTP no están disponibles temporalmente, los tokens de autenticación expiran y los límites de tamaño de los archivos adjuntos varían según el proveedor. Incorpore resiliencia en la ruta de envío de correo electrónico desde el principio.
Envuelva la lógica de envío de MailKit en un try/catch y registre las fallas en una cola persistente para que se puedan volver a intentar:
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
La retirada exponencial (2 segundos después de la primera falla, 4 después de la segunda) evita sobrecargar un servidor SMTP. En aplicaciones de producción, reemplace el bucle de reintento con una cola de mensajes (Azure Service Bus, RabbitMQ o AWS SQS) para que las fallas sobrevivan a los reinicios de la aplicación.
IronPDF también lanza un PdfException si no se puede representar el contenido HTML. Captúrelo por separado de las excepciones SMTP para que el mensaje de error sea específico:
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 los errores de renderizado de los errores de entrega hace que la depuración sea más rápida. Para una visión más amplia del manejo de errores en los procesos automatizados de documentos, la guía de generación de PDF de 5 pasos cubre los patrones de validación en detalle.
¿Cómo mantener el tamaño de los archivos adjuntos dentro de los límites del proveedor?
La mayoría de los proveedores de correo electrónico comerciales imponen un tamaño máximo para los archivos adjuntos. Gmail limita los archivos adjuntos individuales a 25 MB. Microsoft 365 tiene como valor predeterminado 20 MB para buzones de correo estándar. Un informe HTML con mucho estilo y con imágenes incrustadas puede superar estos límites inesperadamente.
Tres técnicas ayudan a mantenerse dentro de los límites:
Comprima las imágenes antes de renderizarlas. Las imágenes en línea deben usar JPEG o WebP comprimidos en lugar de PNG sin comprimir. Un logotipo PNG de 600 dpi puede agregar varios megabytes al PDF; Un JPEG con una calidad del 85% normalmente pesa menos de 200 KB para obtener el mismo resultado visual.
Utilice la configuración de compresión de IronPDF. El método PdfDocument.CompressImages reduce la resolución de los mapas de bits incrustados después de la renderización. Llámalo antes de leer 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 los informes grandes en varios correos electrónicos. Si un informe supera el límite del proveedor, incluso después de la compresión, genere un PDF por sección y envíe cada uno en un correo electrónico independiente. La página de instrucciones para dividir y fusionar PDF muestra cómo dividir un PdfDocument por rango de páginas usando CopyPages.
Referencias externas para los límites de tamaño de SMTP: límites de archivos adjuntos de Gmail , límites de tamaño de mensajes de Microsoft 365 .
¿Cuales son tus próximos pasos?
Ahora tienes una plantilla funcional para generar un PDF en la memoria con IronPDF y enviarlo como archivo adjunto en un correo electrónico usando MailKit o System.Net.Mail. El enfoque en memoria elimina las lecturas y escrituras en disco, simplifica las implementaciones en contenedores y se adapta a escenarios de alto rendimiento sin necesidad de limpieza temporal de archivos.
Para profundizar la integración:
- Lea el tutorial de HTML a PDF para dominar diseños de documentos complejos con encabezados, pies de página y numeración de páginas.
- Explore las opciones de representación de PDF personalizadas para controlar los márgenes, el tamaño de la página y el tiempo de espera de ejecución de JavaScript .
- Agregue una firma digital al PDF generado antes de adjuntarlo, proporcionando a los destinatarios documentos a prueba de manipulaciones.
- Implemente en Azure Functions o App Service para la generación de documentos sin servidor a escala.
- Pruebe IronPDF de forma gratuita para probar el conjunto completo de funciones antes de comprometerse con una licencia de producción, o revise las opciones de licencia para conocer los precios de implementación.
Preguntas Frecuentes
¿Cómo puedo enviar un PDF generado como archivo adjunto de correo electrónico en C#?
Usando IronPDF, puedes enviar archivos PDF generados como archivos adjuntos de correo electrónico integrando sus capacidades de creación de PDF con las funciones de envío de correo electrónico de .NET.
¿Cuáles son las ventajas de enviar archivos PDF por correo electrónico en aplicaciones .NET?
El envío de archivos PDF por correo electrónico en aplicaciones .NET ayuda a automatizar la entrega de documentos, agilizando los flujos de trabajo empresariales y mejorando la comunicación con los clientes.
¿Puede IronPDF gestionar el contenido dinámico de los archivos PDF adjuntos a correos electrónicos?
Sí, IronPDF genera contenido PDF dinámicamente, haciéndolo adecuado para aplicaciones impulsadas por eventos que requieren enviar PDFs personalizados como archivos adjuntos de correo electrónico.
¿Qué parámetros se utilizan habitualmente en los métodos de envío de correo electrónico con IronPDF?
Los parámetros comunes incluyen el asunto del correo electrónico, la información del remitente y EventArgs, que garantizan un procesamiento eficaz en aplicaciones basadas en eventos.
¿Por qué IronPDF es adecuado para automatizar la entrega de documentos?
IronPDF es adecuado para automatizar la entrega de documentos porque proporciona una creación de PDF confiable e integra con las capacidades de envío de correo electrónico de C#.
¿Es posible programar el envío de correos electrónicos en PDF con IronPDF?
Sí, IronPDF puede integrarse en tareas programadas para automatizar el envío de correos electrónicos en PDF en momentos específicos, lo que mejora la eficacia del flujo de trabajo.
¿Es compatible IronPDF con la creación de archivos PDF a partir de diversas fuentes de datos para adjuntarlos a correos electrónicos?
IronPDF admite la creación de PDFs a partir de múltiples fuentes de datos, permitiendo a los desarrolladores generar documentos detallados para archivos adjuntos de correo electrónico.
¿Cómo mejora IronPDF la comunicación por correo electrónico con los clientes?
Al permitir la generación y el envío de documentos PDF detallados como archivos adjuntos, IronPDF mejora la profesionalidad y la claridad de la comunicación por correo electrónico con los clientes.
¿Puede usarse IronPDF para enviar facturas e informes como archivos adjuntos en PDF?
Sí, IronPDF es ideal para generar y enviar facturas, informes y otros documentos como archivos adjuntos en PDF, atendiendo a diversas necesidades empresariales.
¿Qué papel desempeña IronPDF en la mejora de los flujos de trabajo empresariales?
IronPDF mejora los flujos de trabajo empresariales al permitir la creación y distribución de documentos PDF, reduciendo la intervención manual y los errores.


