IRONSOFTWAREHOME
使用IRONPDF

如何构建 .NET HTML 到 PDF 转换器

Curtis Chau
Curtis Chau
Updated: 2026年7月5日

自动化文档交付几乎是每个业务线 .NET 应用程序都会遇到的需求。 订单生成后,发票必须在几秒钟内送达客户。 如果报告是在夜间生成的,利益相关者希望在上班前就能在邮箱里收到。最简单、最通用的交付格式是将PDF文件作为电子邮件附件发送。 本指南将引导您完成C#的完整端到端工作流程——在内存中使用IronPDF生成PDF文档,然后通过MailKit或内置的System.Net.Mail命名空间将其作为电子邮件附件发送,而无需将单个字节写入磁盘。

如何安装所需的软件包?

该工作流程由两个软件包驱动:PDF 生成库和电子邮件发送库。 可以通过 Visual Studio 中的程序包管理器控制台或通过 .NET CLI 安装两者。

PM > Install-Package IronPdf, MailKit

IronPDF 采用基于 Chromium 的渲染引擎,可将 HTML、CSS 和 JavaScript 转换为像素级完美的 PDF 文档。 它可以运行在 Windows、Linux 和 macOS 上,这意味着相同的代码可以在 ASP.NET Core Web API、后台服务或 Azure 函数中使用。 MailKit 是微软推荐用于所有新的 .NET 电子邮件开发的库——它支持 SMTP、IMAP、POP3、OAuth 2.0 和完整的 MIME 构造。 MailKit 的源代码和文档可在 GitHub 上找到。

如何在内存中生成 PDF 文档?

ChromePdfRendererHTML转PDF转换的入口点。 将HTML字符串传递给PdfDocument对象。 通过BinaryData属性访问原始字节——这个字节数组正是电子邮件附件API所期望的。

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");

RenderHtmlAsPdf方法使用与谷歌Chrome相同的Chromium引擎解析HTML,因此表格、CSS网格、Flexbox和嵌入字体在浏览器中呈现的效果完全一致。 结果是BinaryData属性返回完整的PDF二进制,无需任何磁盘读写。 对于需要引入外部图像或样式表的文档,请使用可选的BasePath参数来告诉IronPDF在哪里解析相对资源URL——在HTML文件转PDF指南页中对此进行了详细介绍。

设置页面布局和自定义页眉

在附加 PDF 文件之前,您可能需要配置页边距、页眉或页脚。 所有布局选项都存储在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;

边距以毫米为单位。 {total-pages}令牌在渲染时被替换。HTML字符串转PDF指南页涵盖了完整的渲染选项集。 您还可以在附加之前,在生成的文档上添加水印图文印章

如何使用 MailKit 将 PDF 文件附加到电子邮件中?

MailKit 直接构建 MIME 邮件树,让您可以完全控制内容类型、编码和附件元数据。 BodyBuilder助手类简化了带有一个或多个文件附件的文本或HTML正文的常见情况。

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);

ContentType实例。 异步 SMTP 方法在网络操作完成时保持调用线程空闲——这对于处理数十个并发请求的 ASP.NET Core 控制器至关重要。

AuthenticateAsync。 对于Microsoft 365,如果您的租户禁用了基本认证,请通过MailKit的SaslMechanismOAuth2类配置OAuth 2.0认证。

发送给多个收件人

要在同一封电子邮件中抄送多人,请在调用Bcc集合中:

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"));

单次SendAsync调用将消息发送到所有地址。 MailKit 在一个 SMTP 会话中批量处理 RCPT TO 命令,因此对于多个收件人不会造成性能损失。

如何使用 System.Net.Mail 作为替代方案?

对于面向旧.NET版本的项目或不允许添加第三方NuGet包的项目,内置的System.Net.Mail命名空间可以处理基本SMTP传输。 微软不再建议在新开发项目中使用它,但它涵盖了常见的用例,而且没有额外的依赖项。

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);

与MailKit相比的关键区别在于using语句中,这些语句在发送后会释放SMTP连接并刷新基础流。 如果在using,附件流可能会在某些运行环境中发送完成之前被释放。

在 MailKit 和 System.Net.Mail 之间进行选择

MailKit 与 System.Net.Mail 功能比较
特征MailKitSystem.Net.Mail
OAuth 2.0 身份验证
IMAP/POP3 支持
异步优先 API部分的
微软推荐受到推崇的遗产
附加 NuGet 包必需的无需
复杂的 MIME 构造全面支持基础

对于任何新项目,请选择 MailKit,尤其是在 SMTP 服务器需要 OAuth 或需要 IMAP 读取回复的情况下。 在代码库已经依赖于它且迁移成本不被证明合理时使用System.Net.Mail

如何将此模式应用于实际业务工作流程?

内存中 PDF 转电子邮件模式直接适用于驱动大多数业务应用程序的文档自动化场景。

发票自动化

电子商务订单处理程序会在收到付款后立即生成发票 PDF 文件。 RenderHtmlAsPdf的方法,该方法使用订单数据填充的Razor模板HTML字符串,然后将结果发送到客户的电子邮件地址。 因为PDF从未触及文件系统,所以没有需要清理的残余文件,没有共享临时目录的竞争条件,也没有容器化部署的权限问题。 有关从 Razor 视图渲染 HTML 的更多信息,请参阅ASP.NET Core PDF 生成指南

定期报告分发

使用IHostedService计划的后台服务每周一06:00生成每周分析摘要。 它查询数据库,构建 HTML 报告字符串,使用 IronPDF 渲染,并使用 MailKit 将其发送到邮件列表。整个流程以异步工作流的形式运行,因此在 SMTP 握手期间不会占用线程池线程。 对于 Azure 托管的工作负载, Azure PDF 生成器指南解释了如何在 Azure 应用服务和 Azure Functions 中部署 IronPDF。

在 ASP.NET Core 中生成收据

在 ASP.NET Core 最小 API 或控制器操作中,POST 端点接收结账有效负载,生成收据 PDF,并返回 HTTP 200,同时发送电子邮件。 将电子邮件发送逻辑保留在后台Task中,以便HTTP响应立即返回给客户端:

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." });
});

即使 SMTP 服务器速度较慢,也能将 API 响应时间保持在 100 毫秒以下。 emailService注册为一个范围或瞬态服务,该服务包装MailKit SmtpClient

如何处理错误和重试?

网络运行失败。 SMTP 服务器暂时不可用,身份验证令牌过期,附件大小限制因提供商而异。 从一开始就在电子邮件发送流程中建立弹性。

将 MailKit 的发送逻辑封装在 try/catch 语句中,并将失败情况记录到持久队列中,以便可以重试:

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)));
        }
    }
}

指数退避——第一次失败后 2 秒,第二次失败后 4 秒——可防止对过载的 SMTP 服务器进行猛烈攻击。 在生产应用程序中,用消息队列(Azure 服务总线、RabbitMQ 或 AWS SQS)替换重试循环,以便故障在应用程序重启后仍然存在。

如果HTML内容无法渲染,IronPDF也会抛出PdfException。 将其与 SMTP 异常分开捕获,以便错误消息更具体:

PdfDocument pdf;
try
{
    pdf = renderer.RenderHtmlAsPdf(htmlContent);
}
catch (IronPdf.Exceptions.PdfException ex)
{
    logger.LogError(ex, "PDF rendering failed");
    throw;
}

将渲染错误与交付错误分开,可以加快调试速度。 为了更全面地了解自动化文档管道中的错误处理, 5 步 PDF 生成指南详细介绍了验证模式。

如何将附件大小控制在提供商限制范围内?

大多数商业电子邮件服务商都对附件大小有限制。Gmail 将单个附件的大小限制为 25 MB; Microsoft 365 标准邮箱的默认大小为 20 MB。 样式繁多的 HTML 报表,尤其是嵌入图片的报表,可能会意外地超出这些限制。

三种方法有助于控制在限度之内:

**渲染前请压缩图像。**内嵌图像应使用压缩的 JPEG 或 WebP 格式,而非未压缩的 PNG 格式。 一个 600 dpi 的 PNG 格式 logo 会使 PDF 文件增加几兆字节; 通常情况下,质量为 85% 的 JPEG 图片大小小于 200 KB,但视觉效果却相同。

使用IronPDF的压缩设置。 PdfDocument.CompressImages方法在渲染后降低嵌入位图的分辨率。 在读取BinaryData之前调用它:

pdf.CompressImages(60); // quality 0-100
byte[] compressedPdfBytes = pdf.BinaryData;

**将大型报告拆分成多封邮件发送。**如果报告即使经过压缩后仍然超过服务商的限制,则为每个部分生成一个 PDF 文件,并分别通过单独的邮件发送。 PDF拆分和合并指南页展示了如何使用PdfDocument

SMTP 大小限制的外部参考: Gmail 附件限制Microsoft 365 邮件大小限制

下一步计划是什么?

现在,您已经有一个可运行的模板,可以使用IronPDF在内存中生成PDF,并通过MailKit或System.Net.Mail将其作为电子邮件附件发送。 内存中的方法消除了磁盘读写,简化了容器化部署,并在无需清理临时文件的情况下扩展到高吞吐量场景。

为了深化融合:

Curtis Chau
技术作家

Curtis Chau 拥有卡尔顿大学的计算机科学学士学位,专注于前端开发,精通 Node.js、TypeScript、JavaScript 和 React。他热衷于打造直观且美观的用户界面,喜欢使用现代框架并创建结构良好、视觉吸引力强的手册。

...
阅读更多

相关文章

Key in blue circle

立即获取免费的 30 天试用版密钥

无任何限制。100% 解锁。无需信用卡。

bullet_checked无需信用卡或创建账户无任何限制。100% 解锁。无需信用卡。
  • Logo Aetna
  • Logo NASA
  • Logo GE
  • Logo Porsche
  • Logo USDA
  • Logo Qatar
Join Millions of Engineers who’ve tried IronPDF
预约您的免费现场演示
Booking Badge

深受全球数百万工程师信赖

Iron Software 的客户徽标
获取您的无义务咨询
填写下面的表格或通过sales@ironsoftware.com
您的资料将始终保密。
深受全球数百万工程师信赖
Iron Software 的客户徽标
立即获取您的免费30 天试用密钥
无需信用卡或创建账户