Jak wysłać plik PDF jako załącznik e-mail w C#
Automatyzacja dostarczania dokumentów to wymóg, który pojawia się w niemalnie każdej aplikacji .NET przeznaczonej dla konkretnej branży. Po złożeniu zamówienia faktura musi dotrzeć do klienta w ciągu kilku sekund. Kiedy raport jest generowany w nocy, interesariusze oczekują, że znajdą go w swojej skrzynce odbiorczej, zanim dotrą do biura. Najprostszym i powszechnie obsługiwanym formatem dostarczania jest plik PDF wysłany jako załącznik do wiadomości e-mail. Ten przewodnik przeprowadzi Cię przez kompletny proces w języku C# — generowanie dokumentu PDF w pamięci za pomocą IronPDF, a następnie wysyłanie go jako załącznik do wiadomości e-mail przy użyciu MailKit lub wbudowanej przestrzeni nazw System.Net.Mail, a wszystko to bez zapisywania ani jednego bajtu na dysku.
Jak zainstalować wymagane pakiety?
Ten proces opiera się na dwóch pakietach: bibliotece do generowania plików PDF oraz bibliotece do wysyłania wiadomości e-mail. Zainstaluj oba za pomocą konsoli menedżera pakietów w Visual Studio lub poprzez .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
IronPDF oferuje silnik renderujący oparty na Chromium, który konwertuje HTML, CSS i JavaScript na dokumenty PDF o idealnej rozdzielczości. Działa na systemach Windows, Linux i macOS, co oznacza, że ten sam kod działa w interfejsie API .NET Core, usłudze działającej w tle lub funkcji Azure. MailKit to biblioteka zalecana przez Microsoft do wszystkich nowych projektów związanych z pocztą elektroniczną w środowisku .NET — obsługuje protokoły SMTP, IMAP, POP3, OAuth 2.0 oraz pełną konstrukcję MIME. Kod źródłowy i dokumentacja MailKit są dostępne na GitHubie.
Jak wygenerować dokument PDF w pamięci?
Klasa ChromePdfRenderer stanowi punkt wejścia dla konwersji HTML do PDF. Przekaż ciąg HTML do RenderHtmlAsPdf, a otrzymasz obiekt PdfDocument, który w całości znajduje się w pamięci. Uzyskaj dostęp do surowych bajtów poprzez właściwość BinaryData — ta tablica bajtów jest dokładnie tym, czego oczekują interfejsy API załączników e-mailowych.
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")
Metoda RenderHtmlAsPdf analizuje kod HTML przy użyciu tego samego silnika Chromium, który napędza przeglądarkę Google Chrome, dzięki czemu tabele, CSS Grid, Flexbox i osadzone czcionki są renderowane dokładnie tak samo, jak w przeglądarce. Wynikiem jest PdfDocument, którego właściwość BinaryData zwraca pełny plik binarny PDF bez odczytu i zapisu na dysku. W przypadku dokumentów, które pobierają zewnętrzne obrazy lub arkusze stylów, należy użyć opcjonalnego parametru BasePath, aby wskazać IronPDF, gdzie ma rozwiązać względne adresy URL zasobów — jest to szczegółowo omówione na stronie z instrukcjami dotyczącymi konwersji plików HTML do formatu PDF.
Ustawianie układu strony i niestandardowych nagłówków
Przed dołączeniem pliku PDF warto skonfigurować marginesy, nagłówki lub stopki. Wszystkie opcje układu znajdują się we właściwości 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
Marginesy są podane w milimetrach. Tokeny {page} i {total-pages} są zastępowane w momencie renderowania. Strona z instrukcją konwersji ciągu HTML do formatu PDF zawiera pełen zestaw opcji renderowania. Przed załączeniem wygenerowanego dokumentu można również dodać do niego znaki wodne lub umieścić na nim tekst i obrazy.
Jak załączyć plik PDF do wiadomości e-mail za pomocą MailKit?
MailKit tworzy drzewo komunikatów MIME bezpośrednio, zapewniając pełną kontrolę nad typem zawartości, kodowaniem i metadanymi załączników. Klasa pomocnicza BodyBuilder upraszcza typowy przypadek treści tekstowej lub HTML z jednym lub kilkoma załącznikami.
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 przyjmuje trzy argumenty: nazwę pliku, którą odbiorca widzi w swoim kliencie poczty e-mail, surową tablicę bajtów z pdf.BinaryData oraz instancję ContentType określającą typ MIME jako application/pdf. Asynchroniczne metody SMTP pozwalają na zwolnienie wątku wywołującego na czas trwania operacji sieciowej — ma to kluczowe znaczenie w kontrolerach .NET Core, które obsługują dziesiątki równoczesnych żądań.
SecureSocketOptions.StartTls negocjuje szyfrowany kanał z serwerem SMTP na porcie 587. W przypadku Gmaila użyj hasła aplikacji zamiast hasła do konta: wygeneruj je w sekcji Bezpieczeństwo konta Google > Hasła aplikacji, a następnie przekaż je do AuthenticateAsync. W przypadku Microsoft 365 skonfiguruj uwierzytelnianie OAuth 2.0 za pomocą klasy SaslMechanismOAuth2 w MailKit, jeśli Twój dzierżawca wyłączył uwierzytelnianie podstawowe.
Wysyłanie do wielu odbiorców
Aby wysłać kopię wiadomości e-mail do wielu osób, dodaj adresy do zbiorów To, Cc lub Bcc przed wywołaniem 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"))
Pojedyncze wywołanie SendAsync dostarcza wiadomość na wszystkie adresy. MailKit grupuje polecenia RCPT TO w jednej sesji SMTP, dzięki czemu wysyłanie wiadomości do wielu odbiorców nie powoduje spadku wydajności.
Jak korzystać z System.Net.Mail jako alternatywy?
W przypadku projektów przeznaczonych dla starszych wersji .NET lub projektów, w których nie jest dozwolone dodawanie pakietów NuGet innych firm, wbudowana przestrzeń nazw System.Net.Mail obsługuje podstawową dostawę SMTP. Microsoft nie zaleca już tego rozwiązania do nowych projektów, ale obsługuje ono typowe przypadki użycia bez dodatkowych zależności.
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
Kluczową różnicą w porównaniu z MailKit jest to, że System.Net.Mail.Attachment nie akceptuje bezpośrednio tablicy bajtów — najpierw należy zawrzeć pdf.BinaryData w MemoryStream. Zarówno MailMessage, jak i SmtpClient są zawarte w instrukcjach using, które po wysłaniu zamykają połączenie SMTP i opróżniają strumień bazowy. Jeśli pominiesz using w MailMessage, strumień załączników może zostać usunięty przed zakończeniem wysyłania w niektórych środowiskach uruchomieniowych.
Wybór między MailKit a System.Net.Mail
| Funkcja | MailKit | System.Net.Mail |
|---|---|---|
| Uwierzytelnianie OAuth 2.0 | Tak | Nie |
| Obsługa protokołów IMAP / POP3 | Tak | Nie |
| API oparte na asynchroniczności | Tak | Częściowe |
| Zalecenie firmy Microsoft | Zalecane | Starsze wersje |
| Dodatkowy pakiet NuGet | Wymagane | Nie jest wymagane |
| Złożona konstrukcja MIME | Pełne wsparcie | Podstawowe |
Wybierz MailKit do każdego nowego projektu, zwłaszcza jeśli serwer SMTP wymaga OAuth lub jeśli potrzebujesz IMAP do odczytu odpowiedzi. Użyj System.Net.Mail, gdy kod źródłowy już na tym polega, a koszt migracji jest nieuzasadniony.
Jak zastosować ten wzorzec w rzeczywistych procesach biznesowych?
Wzorzec "PDF do e-maila w pamięci" ma bezpośrednie zastosowanie w scenariuszach automatyzacji dokumentów, które napędzają większość aplikacji biznesowych.
Automatyzacja fakturowania
Moduł obsługi zamówień w sklepie internetowym generuje fakturę w formacie PDF natychmiast po zaksięgowaniu płatności. Zdarzenie OrderConfirmed uruchamia metodę, która wywołuje RenderHtmlAsPdf z ciągiem HTML opartym na szablonie Razor, wypełnionym danymi zamówienia, a następnie wysyła wynik na adres e-mail klienta. Ponieważ plik PDF nigdy nie ma kontaktu z systemem plików, nie ma żadnych pozostałych plików do usunięcia, nie występują warunki wyścigu w współdzielonym katalogu tymczasowym ani problemy z uprawnieniami w wdrożeniach kontenerowych. Więcej informacji na temat renderowania HTML z widoków Razor można znaleźć w przewodniku po generowaniu plików PDF w ASP.NET Core.
Zaplanowana dystrybucja raportów
Usługa działająca w tle, zaplanowana za pomocą IHostedService, generuje cotygodniowe podsumowanie analityczne o godz. 06:00 w każdy poniedziałek. Wysyła zapytanie do bazy danych, tworzy ciąg znaków raportu HTML, renderuje go za pomocą IronPDF i wykorzystuje MailKit do wysłania go na listę dystrybucyjną. Cały proces przebiega jako asynchroniczny przepływ pracy, więc nie zajmuje wątku z puli wątków podczas uzgadniania połączenia SMTP. W przypadku obciążeń hostowanych w Azure przewodnik po generatorze PDF Azure wyjaśnia, jak wdrożyć IronPDF w ramach usługi Azure App Service i Azure Functions.
Generowanie paragonów w ASP.NET Core
W minimalnym API lub akcji kontrolera .NET Core punkt końcowy POST odbiera ładunek transakcji, generuje paragon w formacie PDF i zwraca kod HTTP 200, jednocześnie wysyłając wiadomość e-mail. Zachowaj logikę wysyłania wiadomości e-mail w tle Task, aby odpowiedź HTTP natychmiast powróciła do klienta:
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)
Dzięki temu czas odpowiedzi API pozostaje poniżej 100 ms, nawet gdy serwer SMTP działa wolno. emailService jest zarejestrowany jako usługa o ograniczonym zakresie lub tymczasowa, która otacza MailKit SmtpClient.
Jak radzisz sobie z błędami i ponownymi próbami?
Operacje sieciowe kończą się niepowodzeniem. Serwery SMTP są chwilowo niedostępne, tokeny uwierzytelniające tracą ważność, a limity rozmiaru załączników różnią się w zależności od dostawcy. Od samego początku zadbaj o odporność ścieżki wysyłania wiadomości e-mail.
Zawiąż logikę wysyłania MailKit w try/catch i rejestruj błędy w stałej kolejce, aby można było je ponownie przetestować:
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
Wykładnicze opóźnienie — 2 sekundy po pierwszej niepowodzeniu, 4 po drugiej — zapobiega nadmiernemu obciążaniu przeciążonego serwera SMTP. W aplikacjach produkcyjnych należy zastąpić pętlę ponownych prób kolejką komunikatów (Azure Service Bus, RabbitMQ lub AWS SQS), aby awarie nie miały wpływu na ponowne uruchomienie aplikacji.
IronPDF generuje również błąd PdfException, jeśli nie można wyrenderować treści HTML. Wyłapuj to oddzielnie od wyjątków SMTP, aby komunikat o błędzie był konkretny:
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
Oddzielenie błędów renderowania od błędów dostarczania przyspiesza debugowanie. Aby uzyskać szerszy obraz obsługi błędów w zautomatyzowanych procesach przetwarzania dokumentów, 5-etapowy przewodnik po generowaniu plików PDF szczegółowo omawia wzorce walidacji.
Jak utrzymać rozmiar załącznika poniżej limitów dostawcy?
Większość komercyjnych dostawców poczty elektronicznej nakłada ograniczenia dotyczące maksymalnego rozmiaru załączników. Gmail ogranicza rozmiar pojedynczego załącznika do 25 MB; W usłudze Microsoft 365 domyślny limit dla standardowych skrzynek pocztowych wynosi 20 MB. Bogato sformatowany raport HTML z osadzonymi obrazami może nieoczekiwanie przekroczyć te limity.
Trzy techniki pomagają zachować te ograniczenia:
Kompresuj obrazy przed renderowaniem. Obrazy wbudowane powinny być w formacie skompresowanym JPEG lub WebP, a nie nieskompresowanym PNG. Logo w formacie PNG o rozdzielczości 600 dpi może zwiększyć rozmiar pliku PDF o kilka megabajtów; Plik JPEG o jakości 85% ma zazwyczaj mniej niż 200 KB przy takim samym efekcie wizualnym.
Użyj ustawień kompresji IronPDF. Metoda PdfDocument.CompressImages zmniejsza rozdzielczość osadzonych map bitowych po renderowaniu. Wywołaj przed przeczytaniem 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
Duże raporty należy podzielić na kilka wiadomości e-mail. Jeśli raport przekracza limit dostawcy nawet po kompresji, należy wygenerować jeden plik PDF na sekcję i wysłać każdy z nich w osobnej wiadomości e-mail. Strona z instrukcją dzielenia i łączenia plików PDF pokazuje, jak podzielić PdfDocument według zakresu stron przy użyciu CopyPages.
Zewnętrzne źródła dotyczące limitów rozmiaru w protokole SMTP: limity załączników w Gmailu, limity rozmiaru wiadomości w Microsoft 365.
Jakie są Twoje kolejne kroki?
Masz teraz gotowy szablon do generowania pliku PDF w pamięci za pomocą IronPDF i wysyłania go jako załącznik do wiadomości e-mail przy użyciu MailKit lub System.Net.Mail. Podejście oparte na pamięci operacyjnej eliminuje operacje odczytu i zapisu na dysku, upraszcza wdrożenia kontenerowe i skaluje się do scenariuszy o wysokiej przepustowości bez konieczności czyszczenia plików tymczasowych.
Aby pogłębić integrację:
- Zapoznaj się z samouczkiem dotyczącym konwersji HTML do PDF, aby opanować złożone układy dokumentów z nagłówkami, stopkami i numeracją stron.
- Zapoznaj się z opcjami niestandardowego renderowania plików PDF, aby kontrolować marginesy, rozmiar strony i limit czasu wykonywania kodu JavaScript.
- Dodaj podpis cyfrowy do wygenerowanego pliku PDF przed załączeniem go, zapewniając odbiorcom dokumenty zabezpieczone przed manipulacją.
- Wdroż w Azure Functions lub App Service, aby generować dokumenty bezserwerowo na dużą skalę.
- Wypróbuj IronPDF za darmo, aby przetestować pełen zestaw funkcji przed zakupem licencji produkcyjnej, lub zapoznaj się z opcjami licencyjnymi, aby poznać ceny wdrożenia.
Często Zadawane Pytania
Jak mogę wysłać wygenerowany plik PDF jako załącznik do wiadomości e-mail w języku C#?
Korzystając z IronPDF, można wysyłać wygenerowane pliki PDF jako załączniki do wiadomości e-mail, integrując jego funkcje tworzenia plików PDF z funkcjami wysyłania wiadomości e-mail w .NET.
Jakie są zalety wysyłania plików PDF pocztą elektroniczną w aplikacjach .NET?
Wysyłanie plików PDF pocztą elektroniczną w aplikacjach .NET pomaga zautomatyzować dostarczanie dokumentów, usprawniając przepływ pracy w firmie i poprawiając komunikację z klientami.
Czy IronPDF obsługuje treści dynamiczne w plikach PDF załączanych do wiadomości e-mail?
Tak, IronPDF dynamicznie generuje zawartość plików PDF, dzięki czemu nadaje się do aplikacji sterowanych zdarzeniami, które wymagają wysyłania spersonalizowanych plików PDF jako załączników do wiadomości e-mail.
Jakie parametry są powszechnie używane w metodach wysyłania wiadomości e-mail za pomocą IronPDF?
Typowe parametry obejmują temat wiadomości e-mail, informacje o nadawcy oraz EventArgs, które zapewniają wydajne przetwarzanie w aplikacjach sterowanych zdarzeniami.
Dlaczego IronPDF nadaje się do automatyzacji dostarczania dokumentów?
IronPDF nadaje się do automatyzacji dostarczania dokumentów, ponieważ zapewnia niezawodne tworzenie plików PDF i integruje się z funkcjami wysyłania wiadomości e-mail w języku C#.
Czy za pomocą IronPDF można zaplanować wysyłanie plików PDF pocztą elektroniczną?
Tak, IronPDF można zintegrować z zaplanowanymi zadaniami w celu automatyzacji wysyłania wiadomości e-mail w formacie PDF o określonych porach, co poprawia wydajność przepływu pracy.
Czy IronPDF obsługuje tworzenie plików PDF z różnych źródeł danych na potrzeby załączników do wiadomości e-mail?
IronPDF obsługuje tworzenie plików PDF z wielu źródeł danych, umożliwiając programistom generowanie szczegółowych dokumentów do załączników w wiadomościach e-mail.
W jaki sposób IronPDF usprawnia komunikację e-mailową z klientami?
Umożliwiając generowanie i wysyłanie szczegółowych dokumentów PDF jako załączników, IronPDF zwiększa profesjonalizm i przejrzystość komunikacji e-mailowej z klientami.
Czy IronPDF może służyć do wysyłania faktur i raportów jako załączników w formacie PDF?
Tak, IronPDF doskonale nadaje się do generowania i wysyłania faktur, raportów oraz innych dokumentów jako załączników w formacie PDF, zaspokajając różnorodne potrzeby biznesowe.
Jaką rolę odgrywa IronPDF w usprawnianiu procesów biznesowych?
IronPDF usprawnia procesy biznesowe, umożliwiając tworzenie i dystrybucję dokumentów PDF, co ogranicza ręczne interwencje i błędy.




