跳過到頁腳內容
使用IRONPDF

如何在C#中以電子郵件附件形式發送PDF文件

自動化文件交付是幾乎所有業務線 .NET 應用程式都會遇到的需求。 訂單產生後,發票必須在幾秒鐘內送達客戶。 如果報告是在夜間產生的,利害關係人希望在上班前就能在郵箱裡收到。最簡單、最通用的交付格式是將PDF文件作為電子郵件附件發送。 本指南將引導您完成 C# 中的完整端到端工作流程——使用IronPDF在內存中生成 PDF 文檔,然後使用 MailKit 或內置的 System.Net.Mail 命名空間將其作為電子郵件附件發送,所有這些都無需向磁碟寫入一個字節。

如何安裝所需的軟體包?

此工作流程由兩個軟體包驅動:PDF 生成庫和電子郵件發送庫。 可以透過 Visual Studio 中的套件管理器控制台或透過 .NET CLI 安裝兩者。

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 採用基於 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 文件?

ChromePdfRenderer 類別HTML 到 PDF 轉換的入口點。 將 HTML 字串傳遞給 RenderHtmlAsPdf,您將得到一個完全駐留在記憶體中的 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");
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

RenderHtmlAsPdf 方法使用與 Google Chrome 相同的 Chromium 引擎解析 HTML,因此表格、CSS Grid、Flexbox 和嵌入式字體都與瀏覽器中呈現的效果完全相同。 結果是一個 PdfDocument,其 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;
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

邊距單位為毫米。 {page}{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);
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 接受三個參數:收件者在其電子郵件用戶端中看到的檔案名稱、來自 pdf.BinaryData 的原始位元組數組,以及指定 MIME 類型為 ContentType 的實例。 非同步 SMTP 方法在網路操作完成時保持呼叫線程空閒——這對於處理數十個並發請求的 ASP.NET Core 控制器至關重要。

SecureSocketOptions.StartTls 與 SMTP 伺服器在 587 連接埠協商加密通道。對於 Gmail,請使用應用程式密碼而不是您的帳戶密碼:在 Google 帳戶安全性 > 應用密碼下產生一個應用程式密碼,然後將其傳遞給 AuthenticateAsync。 對於 Microsoft 365,如果您的租用戶已停用基本驗證,請透過 MailKit 的 SaslMechanismOAuth2 類別設定 OAuth 2.0 驗證。

傳送給多個收件人

若要將多個人副本至同一封電子郵件,請在呼叫 SendAsync 之前,將地址新增至 ToCcBcc 集合中:

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

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

與 MailKit 的主要區別在於,System.Net.Mail.Attachment 不直接接受位元組陣列-您必須先將 pdf.BinaryData 包裝在 MemoryStream 中。 MailMessageSmtpClient 都包裝在 using 語句中,這些語句會在發送郵件後釋放 SMTP 連接並刷新底層流。 如果在 MailMessage 中省略 using,則在某些運行時,附件流可能會在發送完成之前被釋放。

在 MailKit 和 System.Net.Mail 之間進行選擇

MailKit 與 System.Net.Mail 功能比較
特點 MailKit System.Net.Mail
OAuth 2.0 身份驗證
IMAP/POP3 支持
同步第一的 API 部分
微軟推薦 受到推崇的 遺產
附加 NuGet 套件 必填 無需
複雜的 MIME 構造 全面支援 基本

對於任何新項目,請選擇 MailKit,尤其是在 SMTP 伺服器需要 OAuth 或需要 IMAP 讀取回應的情況下。 當程式碼庫已經依賴 System.Net.Mail 且遷移成本不合理時,請使用 System.Net.Mail

如何將此模式應用於實際業務工作流程?

記憶體中 PDF 轉電子郵件模式直接適用於驅動大多數業務應用程式的文件自動化場景。

發票自動化

電子商務訂單處理程序會在收到付款後立即產生發票 PDF 檔案。 OrderConfirmed 事件觸發一個方法,該方法使用從訂單資料填充的 Razor 範本 HTML 字串呼叫 RenderHtmlAsPdf,然後將結果傳送到客戶的電子郵件地址。 由於 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,同時傳送電子郵件。 將郵件傳送邏輯放在背景執行,以便 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." });
});
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

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

指數退避——第一次失敗後 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;
}
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

將渲染錯誤與交付錯誤分開,可以加快調試速度。 為了更全面地了解自動化文件管道中的錯誤處理, 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.CompressImages(60); // quality 0-100
byte[] compressedPdfBytes = pdf.BinaryData;
pdf.CompressImages(60) ' quality 0-100
Dim compressedPdfBytes As Byte() = pdf.BinaryData
$vbLabelText   $csharpLabel

將大型報告拆分成多封郵件發送。如果報告即使經過壓縮後仍然超過服務商的限制,則為每個部分產生一個 PDF 文件,並分別透過單獨的郵件發送。 PDF 分割和合併操作指南頁面展示如何使用 CopyPages 按頁面範圍分割 PdfDocument

SMTP 大小限制的外部參考: Gmail 附件限制Microsoft 365 郵件大小限制

下一步計劃是什麼?

現在您有了一個可以使用 IronPDF 在記憶體中產生 PDF 並使用 MailKit 或 System.Net.Mail 將其作為電子郵件附件發送的工作範本。 記憶體方法消除了磁碟讀寫操作,簡化了容器化部署,並且可以擴展到高吞吐量場景,而無需臨時檔案清理。

為了深化融合:

常見問題解答

如何使用 C# 將產生的 PDF 作為電子郵件附件傳送?

使用IronPDF,您可以將生成的PDF文件作為電子郵件附件發送,通過將其PDF創建功能與.NET的電子郵件發送功能集成。

在 .NET 應用程式中透過電子郵件傳送 PDF 檔案有什麼好處?

在 .NET 應用程式中透過電子郵件傳送 PDF 檔案有助於自動化文件傳送、簡化業務工作流程並加強客戶溝通。

IronPDF 能否處理 PDF 中用於電子郵件附件的動態內容?

是的,IronPDF動態生成PDF內容,適合需要將自訂PDF作為電子郵件附件發送的事件驅動應用程式。

IronPDF 的電子郵件發送方法通常使用哪些參數?

常見的參數包括電子郵件主題、寄件者資訊以及 EventArgs,以確保在事件驅動的應用程式中能有效率地處理。

為什麼 IronPDF 適合自動化文件傳送?

IronPDF適用於自動化文件交付,因為它提供可靠的PDF創建並與C#電子郵件發送功能集成。

是否可以使用 IronPDF 排程發送 PDF 電子郵件?

是的,IronPDF 可以整合到排程任務中,在指定時間自動發送 PDF 電子郵件,提高工作流程效率。

IronPDF 是否支援從各種資料來源建立 PDF 作為電子郵件附件?

IronPDF支援從多個數據源創建PDF,使開發人員能夠生成詳細的文件用作電子郵件附件。

IronPDF 如何加強與客戶的電子郵件溝通?

IronPDF 允許以附件形式生成和發送詳細的 PDF 文件,從而提高了與客戶進行電子郵件溝通的專業性和清晰度。

IronPDF可用於將發票和報告作為PDF附件發送嗎?

是的,IronPDF非常適合於生成和發送發票、報告及其他文件作為PDF附件,滿足各種業務需求。

IronPDF 在改善業務工作流程方面扮演什麼角色?

IronPDF通過啟用PDF文件的創建和發送,減少手動干預和錯誤,提高了業務工作流程的效率。

Curtis Chau
技術作家

Curtis Chau 擁有卡爾頓大學計算機科學學士學位,專注於前端開發,擅長於 Node.js、TypeScript、JavaScript 和 React。Curtis 熱衷於創建直觀且美觀的用戶界面,喜歡使用現代框架並打造結構良好、視覺吸引人的手冊。

除了開發之外,Curtis 對物聯網 (IoT) 有著濃厚的興趣,探索將硬體和軟體結合的創新方式。在閒暇時間,他喜愛遊戲並構建 Discord 機器人,結合科技與創意的樂趣。

鋼鐵支援團隊

我們每週 5 天,每天 24 小時在線上。
聊天
電子郵件
打電話給我