Saltar al pie de página
USANDO IRONPDF

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
SHELL

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")
$vbLabelText   $csharpLabel

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
$vbLabelText   $csharpLabel

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
$vbLabelText   $csharpLabel

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"))
$vbLabelText   $csharpLabel

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
$vbLabelText   $csharpLabel

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

Comparación de características de MailKit vs System .NET.Mail
Función MailKit System.Net.Mail
Autenticación OAuth 2.0 No
Compatibilidad con IMAP/POP3 No
API asíncrona 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)
$vbLabelText   $csharpLabel

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
$vbLabelText   $csharpLabel

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
$vbLabelText   $csharpLabel

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
$vbLabelText   $csharpLabel

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:

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.

Curtis Chau
Escritor Técnico

Curtis Chau tiene una licenciatura en Ciencias de la Computación (Carleton University) y se especializa en el desarrollo front-end con experiencia en Node.js, TypeScript, JavaScript y React. Apasionado por crear interfaces de usuario intuitivas y estéticamente agradables, disfruta trabajando con frameworks modernos y creando manuales bien ...

Leer más

Equipo de soporte de Iron

Estamos disponibles online las 24 horas, 5 días a la semana.
Chat
Email
Llámame