PDF file in email content

This public forum is for user-to-user discussions of ASP.NET Maker. Note that this is not support forum.
Post Reply
aiden
User
Posts: 29

PDF file in email content

Post by aiden »

I have put the invoice as a PDF file in the email content, but when I open the PDF, the file does not open even when I download it. Is there something wrong with the code?

public bool Email_Sending(EmailBase email, dynamic? args) {
    // E-mail naar klant;
    if (CurrentPageID() == "edit") {
        email.Sender = "dp@selexions.nl";
        email.Recipient = "aiden.messi23@gmail.com";
        email.Cc = "";  
        email.Bcc = "";
        email.Subject = "factuur test";
        email.Content = "Hierbij ontvangt u de factuur in de onderstaande bijlage";
        email.Format = "html";
        email.Charset = "utf-8";

        // HTML content voor de PDF
        string htmlContent =  @"
<!DOCTYPE html>
<html lang='nl'>
<head>
    <meta charset='UTF-8'>
    <meta name='viewport' content='width=device-width, initial-scale=1.0'>
    <title>Factuur</title>
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 0;
            padding: 0;
            background: #f4f4f4;
        }
        img#logo {
            display: none !important;
        }
        .main-footer {
            display: none !important;
        }
        .container5 {
            margin: 0 auto;
            padding: 20px;
        }
        .header5 {
            text-align: center;
            margin-bottom: 20px;
        }
        .header-image5 {
            width: 100%;
            display: block;
            margin: 0 auto;
        }
        .contact-info5 {
            background: #fd7e14;
            padding: 10px;
            text-align: center;
            margin-bottom: 20px;
        }
        .contact-info5 p {
            margin: 0;
            white-space: nowrap;
        }
        .details5 {
            display: flex;
            justify-content: space-between;
            margin-bottom: 20px;
        }
        .details5 .left5, .details5 .right5 {
            width: 48%;
        }
        .details5 .right5 {
            text-align: right;
        }
        .invoice5 {
            margin-bottom: 20px;
        }
        .invoice-header5, .invoice-item5 {
            display: flex;
            justify-content: space-between;
            padding: 8px 0;
            word-break: break-word;
        }
        .invoice-header5 {
            font-weight: bold;
            border-bottom: 1px solid #000;
        }
        .invoice-item5 span {
            white-space: pre-wrap;
            margin-top: -40px;
        }
        .totals5 {
            text-align: right;
            margin-top: 125px;
        }
        .totals5 .total-item5 {
            display: flex;
            justify-content: space-between;
        }
        .bank-info5 {
            margin-bottom: 20px;
            float: left;
            text-align: left;
            margin-top: 125px;
        }
        .bank-info5 p {
            margin: 5px 0;
        }
        .payment-info {
            margin-top: 20px;
            font-weight: bold;
        }
        .right, .right-extended {
            display: flex;
            justify-content: flex-end;
            align-items: center;
        }
        .right > div, .right-extended > div {
            text-align: right;
            white-space: nowrap;
            width: 108px;
        }
        .right-extended > div > p:first-child {
            border-bottom: 1px solid #000;
            padding-bottom: 4px;
        }
    </style>
</head>
<body>
    <div class='container5'>
        <div class='header5'>
            <a href='https://www.klankschalenlimburg.nl/' target='_blank'><img src='https://www.selexions.nl/uploadfiles/klank.jpg' alt='Klankschalen Limburg' style='width: 100%; display: block; margin: 0 auto;' /></a>
            <div class='contact-info5'>
                <p>Barbarastraat 26, Geleen, Telefoonnummer: 046-4110136, E-mail: info@klankschalenlimburg.nl</p>
            </div>
        </div>
        <div class='details5'>
            <div class='left5'>
                <p>{{{dbvalue FactuurNaam}}}</p>
                <p>{{{dbvalue FactuurAdres}}}</p>
                <p>{{{dbvalue FactuurPostcode}}}</p>
                <p>{{{dbvalue FactuurPlaats}}}</p>
            </div>
            <div class='right5'>
                <p>Geleen, {{{value FactuurDatum}}}</p>
            </div>
        </div>
        <div class='invoice5'>
            <div class='invoice-header5'>
                <span>Beschrijving</span>
            </div>
            <div class='invoice-item5'>
                <span>{{{value FactuurOmschrijving}}}</span>
            </div>
        </div>
        <div class='totals5'>
            <div class='bank-info5'>
                <p>Rabobank Geleen NL88RABO01160.10.568</p>
                <p>KvK Zuid-Limburg 14052069</p>
                <p>BTW-nummer 8140.10.532.B01</p><br><br><br>
            </div>
            <div class='right-extended'>
                <div>
                    <p>Sub-totaal</p>
                    <p>{{{dbvalue FactuurPrijs}}}</p>
                </div>
                <div>
                    <p>BTW 21%</p>
                    <p>{{{dbvalue FactuurBtwBedrag}}}</p>
                </div>
                <div>
                    <p>Totaal</p>
                    <p>{{{dbvalue FactuurPrijsInclusiefBtw}}}</p>
                </div>
            </div>
        </div>
        <div class='payment-info'>
            <p>Gelieve te betalen voor {{{dbvalue FactuurDatumBetalingstermijn}}}, ondervermelding van uw naam en factuurdatum.</p>
        </div>
    </div>
</body>
</html>";

        // Generate PDF
        string pdfFileName = "Factuur.pdf";
        using (MemoryStream memoryStream = new MemoryStream()) {
            Document document = new Document();
            PdfWriter writer = PdfWriter.GetInstance(document, memoryStream);
            document.Open();

            // Convert the MemoryStream to a byte-array
            byte[] pdfBytes = memoryStream.ToArray();

            // Attach PDF to email
            string pdfContent = Convert.ToBase64String(pdfBytes);
            email.AddAttachment(pdfFileName, pdfContent);
        }
    }

    return true;
}

MichaelG
User
Posts: 1160

Post by MichaelG »

Your content is in html and you need to convert to pdf first. Please refer to the Export function in "Models/src/ExportPdf".


aiden
User
Posts: 29

Post by aiden »

we have this code in the Exportpdf.cs. how can we convert the html to pdf with this? so that we send the pdf as an attachment in the email content.

Exportpdf.cs:

namespace ASPNETMaker2024.Models;

// Partial class
public partial class klankschalen {
    /// <summary>
    /// Export to PDF class
    /// </summary>
    public class ExportPdf : AbstractExport
    {
        public override string FileExtension { get; set; } = "pdf";

        public HtmlToPdfBuilder PdfBuilder = new();

        private string _tableHeader = "<table class=\"ew-table\">";

        // Constructor
        public ExportPdf(object tbl) : base(tbl)
        {
            if (Table != null) {
                PdfBuilder.SetPaper(Table.ExportPageSize, Table.ExportPageOrientation);
                if (Table.ExportColumnWidths.Length > 0)
                    PdfBuilder.AddColumnWidths(Table.ExportColumnWidths);
            }
        }

        // Table header
        public override void ExportTableHeader() => Text.AppendLine(_tableHeader);

        // Export a value (caption, field value, or aggregate)
        public override void ExportValue(DbField fld, object val)
        {
            Text.AppendLine("<td" + (ExportStyles ? fld.CellStyles : "") + ">" + ConvertToString(val) + "</td>");
        }

        // Begin a row
        public override void BeginExportRow(int rowCnt = 0)
        {
            FieldCount = 0;
            if (Horizontal) {
                string className = rowCnt switch {
                    -1 => "ew-table-footer",
                    0 => "ew-table-header",
                    _ => (rowCnt % 2) == 1 ? "ew-table-row" : "ew-table-alt-row"
                };
                Text.Append("<tr" + (ExportStyles ? " class=\"" + className + "\"" : "") + ">");
            }
        }

        // End a row
        public override void EndExportRow(int rowCnt = 0)
        {
            if (Horizontal)
                Text.Append("</tr>");
        }

        // Page break
        public override void ExportPageBreak()
        {
            if (Horizontal) {
                Text.AppendLine("</table>"); // End current table
                Text.AppendLine(Config.PageBreakHtml); // Page break
                Text.AppendLine(_tableHeader); // New page header
            }
        }

        // Export a field
        public override async Task ExportField(DbField fld)
        {
            if (!fld.Exportable)
                return;
            string value = fld.ExportValue;
            if (fld.ExportFieldImage && fld.ViewTag == "IMAGE") {
                value = GetFileImgTag(await fld.GetTempImage());
            } else if (fld.ExportFieldImage && fld.ExportHrefValue is Func<string, Task<string>> func) { // Export Custom View Tag // DN
                value = await func("pdf"); // DN
            } else {
                value = value.Replace("<br>", "\r\n");
                value = RemoveHtml(value);
                value = value.Replace("\r\n", "<br>");
            }
            if (Horizontal) {
                ExportValue(fld, value);
            } else { // Vertical, export as a row
                FieldCount++;
                fld.CellCssClass = (FieldCount % 2 == 1) ? "ew-table-row" : "ew-table-alt-row";
                Text.Append("<tr><td" + (ExportStyles ? fld.CellStyles : "") + ">" + fld.ExportCaption + "</td>");
                Text.Append("<td" + (ExportStyles ? fld.CellStyles : "") + ">" + value + "</td></tr>");
            }
        }

        // Get style tag
        public async Task<string> StyleTag()
        {
            if (ExportStyles && !Empty(Config.PdfStylesheetFilename)) {
                string content = await LoadText(Config.PdfStylesheetFilename);
                if (!Empty(content))
                    return "<style type=\"text/css\">" + content + "</style>\r\n";
            }
            return "";
        }

        // Add HTML tags
        public override async Task ExportHeaderAndFooter()
        {
            string header = "<html><head>\r\n";
            header += CharsetMetaTag();
            header += await StyleTag();
            header += "</head><body>";
            Text.Insert(0, header);
            Text.Append("</body></html>");
        }

        /// <summary>
        /// Add image
        /// </summary>
        /// <param name="imageFile">Image file name</param>
        /// <param name="breakType">Page break type (before / after)</param>
        public override void AddImage(string imageFile, string breakType = "")
        {
            if (FileExists(imageFile)) {
                string html = "<table class=\"ew-chart\"><tr><td>" + GetFileImgTag([imageFile])  + "</td></tr></table>";
                if (Text.ToString().Contains("</body>"))
                    Text.Replace("</body>", html + "</body>"); // Insert before </body>
                else
                    Text.Append(html); // Append to end
            }
        }

        // Adjust HTML before export
        protected override async Task AdjustHtml()
        {
            var doc = GetDocument(); // Load Text

            // Remove empty charts / Replace div.ew-chart with table.ew-chart
            foreach (var div in doc.QuerySelectorAll("div.ew-chart")) {
                var parent = div.ParentElement;
                var script = parent?.QuerySelector("script");
                if (script != null) // Remove script for chart
                    script.Remove();
                var img = div.QuerySelector("img");
                if (img == null) { // No image inside => Remove
                    div.Remove();
                } else { // Replace div.ew-chart with table.ew-chart
                    var tbl = new AngleSharp.Html.Parser.HtmlParser().ParseDocument("<table class=\"ew-chart\"><tr><td>" + img.OuterHtml + "</td></tr></table>");
                    div.Replace(tbl.QuerySelector("table"));
                }
            }

            // Remove empty cards
            foreach (var div in doc.QuerySelectorAll("div.card")) {
                var selector = div.QuerySelector(Selectors);
                if (selector == null) // Nothing to export => Remove
                    div.Remove();
            }

            // Adjust table class and images
            var tables = doc.QuerySelectorAll(Selectors);
            foreach (var table in tables) {
                string classNames = table.GetAttribute("class") ?? "";
                if (ContainsClass(classNames, "no-border")) // Remove border // DN
                    table.SetAttribute("border", "0");
                if (ContainsClass(classNames, "ew-table"))
                    table.SetAttribute("class", "ew-table"); // Remove other classes
                table.RemoveAttribute("style"); // Remove any style
                var imgs = table.QuerySelectorAll("img");
                foreach (var img in imgs) { // Images
                    string fn = img.GetAttribute("src") ?? "";
                    byte[] data;
                    if (fn.StartsWith("data:")) { // Handle base64 image
                        fn = await TempImageFromBase64Url(fn);
                    } else {
                        if (FileExists(fn)) {
                            data = await FileReadAllBytesAsync(fn);
                        } else {
                            fn = FullUrl(fn);
                            data = await DownloadDataAsync(fn);
                        }
                        fn = await TempImage(data);
                    }
                    if (!FileExists(fn))
                        continue;
                    img.SetAttribute("src", fn);
                }
            }

            // Add page break
            string html = "";
            if (Table?.ExportPageBreaks ?? ExportPageBreaks) {
                var els = doc.QuerySelectorAll(Selectors);
                int i = 0;
                foreach (var el in els) {
                    if (i > 0)
                        html += Config.PageBreakHtml;
                    html += el.OuterHtml;
                    el.Remove();
                    i++;
                }
                // html += doc.QuerySelector("body")?.InnerHtml ?? "";
            } else {
                var body = doc.QuerySelector("body");
                html = body == null ? doc.DocumentElement.OuterHtml : body.InnerHtml;
            }
            Text.Clear();
            Text.Append(html);

            // Add CSS for PDF
            await ExportHeaderAndFooter();
        }

        // Export
        public override async Task<IActionResult> Export(string fileName = "", bool output = true, bool save = false)
        {
            await AdjustHtml();
            try {
                PdfBuilder.LoadHtml(Text.ToString());
                byte[] data;
                using (MemoryStream ms = await PdfBuilder.RenderPdf()) {
                    ms.Seek(0, SeekOrigin.Begin);
                    data = ms.ToArray(); // Use byte array
                }

                // Save to folder
                if (save)
                    await SaveFile(ExportPath(true), GetSaveFileName(), data);

                // Output
                if (output) {
                    WriteHeaders(fileName);
                    return Controller.File(data, GetContentType().ToString());
                }
            } catch {
                if (Config.Debug)
                    throw;
            }
            return new EmptyResult();
        }
    }
} // End Partial class

MichaelG
User
Posts: 1160

Post by MichaelG »

Your content is in html and you need to convert to pdf first. Please refer to the Export function in "Models/src/ExportPdf".

Check the codes for PdfBuilder.LoadHtml and PdfBuilder.RenderPdf.


Post Reply