Page 1 of 1

PDF file in email content

Posted: Wed Jun 19, 2024 5:13 pm
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;
}

Re: PDF file in email content

Posted: Thu Jun 20, 2024 7:52 am
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".


Re: PDF file in email content

Posted: Thu Jun 20, 2024 3:14 pm
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

Re: PDF file in email content

Posted: Fri Jun 21, 2024 7:55 am
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.