Generating payment invoices is a crucial aspect of any business, and digital invoicing has become a common practice across various industries. In this context, web application developers often face the task of programmatically generating and sending PDF invoices. Whether you’re automating the Invoice generation and notification process or developing a graphical user Interface (GUI) to proactively remind clients about outstanding Invoices, the initial technical challenge lies in generating PDF Invoices. While you could develop a custom script for PDF generation, that would be a significant undertaking. While web-based services are convenient, they may not be suitable if you have confidentiality agreements with your clients since sending data to a third-party service over the internet can pose concerns. Fortunately, Foxit’s provides a quick and secure solution for generating PDF files. By utilizing their , you can convert any HTML document, including Invoices, into a PDF file that can be attached to an email or made available for clients to download from your web application. PDF library HTML to PDF converter This tutorial will guide you through the process of creating a application that leverages the to generate PDF Invoices from HTML Invoices within a web app. Once generated, you will utilize to send the Invoice via SMTP to the client’s email address. You can follow the steps outlined below or . Node.js Foxit PDF SDK Nodemailer access the complete codebase on Foxit’s GitHub repository Building a Web Application to Create and Send PDF Invoices In this tutorial, we will walk you through the process of building a web application that enables your billing department to manage unpaid invoices effectively. You will create various features, including an internal tool for follow-up, a page displaying outstanding invoices, and a preview page for each Invoice. Users will have the option to send email reminders to clients with the attached Invoice. For this project, we will be utilizing the web framework, for styling, and for email functionality. Express Pure CSS Nodemailer Prerequisites: version 8+ and version 5+ Node.js NPM The Foxit SDK (you can version from their website) download a free trial The Foxit HTML to PDF conversion add-on (optional, for testing SMTP email transport) Mailtrap Creating a New Express App To create a new boilerplate Express web application, you need to use the : app generator npx express-generator --git --view=hbs This will create a web app with a file and template files. .gitignore Handlebars Next, you need to add the Nodemailer npm package and install Express’ dependencies: npm i nodemailer && npm i The default application generated by Express provides you with two route files: and . Remove the route and create a new route file called . Add this new route to your file and remove the : /routes/index.js /routes/users.js users.js invoices.js app.js usersRoute ... var indexRouter = require('./routes/index'); var invoicesRouter = require('./routes/invoices'); var app = express(); ... app.use('/', indexRouter); app.use('/invoices', invoicesRouter); ... The bulk of the work in this application is within the invoices router. Before you create the route, you’ll need some data you can use. In a real application, you’ll likely connect to a database, but for demo purposes, add your invoice data to a JSON file. Create a new file at and add the below: /data/invoices.json [ { "id": "47427759-9362-4f8e-bfe4-2d3733534e83", "customer": "Bins and Sons", "contact_name": "Verne McKim", "contact_email": "vmckim0@example.com", "address": "3 Burning Wood Street", "city_state": "Memphis, TN 38118", "plan_id": "41595-5514", "plan_name": "Starter", "subtotal": 499.99, "fee": 50.00, "total": 549.99 }, { "id": "1afdd2fa-6353-437c-a923-e43baac506f4", customer": "Koepp Group", "contact_name": "Junia Pretious", "contact_email": "jpretious1@example.com", "address": "7170 Fairfield Hill", "city_state": "Los Angeles, CA 90026", "plan_id": "43419-355", "plan_name": "Professional", "amount": 999.99, "fee": 50.00, "total": 1049.99 }, { "id": "59c216f8-7471-4ec2-a527-ab3641dc49aa", "customer": "Lynch-Bednar", "contact_name": "Evelin Stollenberg", "contact_email": "estollenberg2@example.com", "address": "9951 Erie Place", "city_state": "Chicago, IL 60605", "plan_id": "63323-714", "plan_name": "Starter", "amount": 499.99, "fee": 50.00, "total": 549.99 } ] The three invoices you can see above contain customer, plan, and billing data which will help you generate an invoice in the next section. Creating the Invoices Routes The file will create three new routes within your application: routes/invoices.js – A list of all the invoices from the flat data file above. /invoices – An invoice preview so users can see what the invoice will look like before they send it to the client. /invoices/:id – An endpoint that generates and sends the PDF invoice to the contact email which is on file. /invoices/:id/email Open the file and add the following code snippet to define the first two routes: invoices.js const express = require('express'); const router = express.Router(); const invoices = require('../data/invoices.json'); // Import exec to run the Foxit HTML to PDF executable const { exec } = require('child_process'); // Import nodemailer to send emails const nodemailer = require('nodemailer'); router.get('/', function(req, res) { res.render('invoice-list', { invoices: invoices, // Accepts errors and successes as query string arguments success: req.query['success'], error: req.query['error'], }); }); router.get('/:id', function(req, res) { const invoice = invoices.find(invoice => invoice.id === req.params['id']); // If the invoice doesn't exist, redirect the user back to the list page if (!invoice) { res.redirect('/invoices'); } // Make the date format pretty const date = new Date().toLocaleDateString("en", { year:"numeric", day:"2-digit", month:"2-digit", }); res.render('invoice-single', { invoice, date }); }); router.get('/:id/email', function(req, res) { // Coming soon. }); module.exports = router; Your application is nearly ready to test, but you need to create the two view files first. Adding Views and Styles Express separates logic and presentation into and . Now add two new files to the directory: and . routes/ views/ views/ invoice-list.hbs invoice-single.hbs Also, add the following to your file: invoice-list.hbs <h1><a href="/invoices">Unpaid Invoices</a></h1> {{#if success}} <p class="success"><strong>Success!</strong> The invoice has been sent to the client.</p> {{/if}} {{#if error}} <p class="error"><strong>Whoops!</strong> Something went wrong and your invoice could not be sent.</p> {{/if}} {{#each invoices}} <h3>{{this.customer}}</h3> <p>ID: {{this.id}} <br/> <a href="/invoices/{{this.id}}">View</a> | <a href="/invoices/{{this.id}}/email">Email Reminder</a> </p> {{/each}} Open th file and add this: e invoice-single.hbs <div class="pure-g"> <div class="pure-u-1-2"> <h1>Invoice</h1> </div> <div class="pure-u-1-2" style="text-align: right;"> <p class="muted">Issued on {{ date }}</p> </div> </div> <div class="pure-g"> <div class="pure-u-1-2"> <h3>Provider</h3> <p> <strong>Tiller, Inc.</strong><br/> 1255 S. Clark<br/> Chicago, IL 60608 </p> </div> <div class="pure-u-1-2" style="text-align: right;"> <h3>Billed to</h3> <p> <strong>{{invoice.customer}}</strong><br/> {{invoice.contact_name}}<br/> {{invoice.address}}<br/> {{invoice.city_state}} </p> </div> </div> <table class="pure-table pure-table-horizontal"> <thead> <tr> <th>ID</th> <th>Plan Name</th> <th class="text-right">Amount</th> </tr> </thead> <tbody> <tr> <td>{{invoice.plan_id}}</td> <td>{{invoice.plan_name}}</td> <td class="text-right">${{invoice.subtotal}}</td> </tr> <tr> <td></td> <td class="text-right">Subtotal:</td> <td class="text-right">${{invoice.subtotal}}</td> </tr> <tr> <td></td> <td class="text-right">Taxes and Fees:</td> <td class="text-right">${{invoice.fee}}</td> </tr> <tr class="bold"> <td></td> <td class="text-right">Total:</td> <td class="text-right">${{invoice.total}}</td> </tr> </tbody> </table> <div class="footer"> <p>Please make checks payable to <strong>Tiller, Inc</strong>. Invoices are due 30 days after date issued.</p> <p>Thank you for your business!</p> </div> To add styles to your application’s stylesheet and incorporate the for a visually appealing look, please open the file and replace its contents with the following code snippet. This will import Pure and create a single column grid layout: Pure CSS module views/layout.hbs <!DOCTYPE html> <html> <head> <title>{{title}}</title> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="stylesheet" href="https://unpkg.com/purecss@2.0.3/build/pure-min.css" integrity="sha384-cg6SkqEOCV1NbJoCu11+bm0NvBRc8IYLRGXkmNrqUBfTjmMYwNKPWBTIKyw9mHNJ" crossorigin="anonymous"> <link rel='stylesheet' href='/stylesheets/style.css' /> </head> <body> <div class="container"> <div class="pure-g"> <div class="pure-u-1"> {{{body}}} </div> </div> </div> </body> </html> Open your application’s and add the following CSS code snippet: public/style.css file body { background-color: #f7f7f7; color: #333333; } a { color: #156d6a; } h1 a, h2 a, h3 a { text-decoration: none; } table { width: 100%; } .container { background-color: #ffffff; max-width: 700px; margin: 0 auto; padding: 30px; } .muted { color: #999999; } .bold { font-weight: bold; } .text-right { text-align: right; } .footer p { margin-top: 30px; } .success { background-color: #c0f5f3; color: #0d928d; padding: 10px; } .error { background-color: #f5c0c0; color: #792525; padding: 10px; } While it is not mandatory, adding styles to your invoices can enhance their professional appearance, as Foxit captures all the styling from your HTML document when generating PDFs. Now, you are ready to test your application. Please start in your command line interface and open your web browser to You will be presented with a list of invoices similar to the following: run npm localhost:3000/invoices Click on “View” to preview each invoice. In the final two steps, you will utilize the Foxit__ __ to generate PDF invoices. Once the invoices are generated, you will then proceed to attach them to an email using Nodemailer before sending them. HTML to PDF tool Generating PDFs with Foxit Foxit’s SDK offers a range of functionalities for PDF creation and manipulation, including the ability to generate a PDF file from an HTML document or URL. The process of downloading and compiling the HTML to PDF executable is available . Once you have successfully executed the demo from your command line, you can proceed with the next steps. here Node’s library includes a function called that enables you to execute command-line functions. This method is useful for running C++ executables from Foxit. To execute the HTML to PDF executable, please update your route with the following code: child_process exec() /:id/email ... router.get('/:id/email', function(req, res) { // Set the executable path and output folder const htmlToPdfPath = '/path/to/foxit/html2pdf'; const outputFolder = __dirname + '/../invoices/'; // Get the invoice const invoice = invoices.find(invoice => invoice.id === req.params['id']); if (!invoice) { res.redirect('/invoices?error=1'); } // Convert the HTML to PDF exec( `${htmlToPdfPath} -html /invoices/${req.params['id']} -o ${outputFolder}${req.params['id']}.pdf`, (err, stdout, stderr) => { if (err || stderr) { console.error(err, stderr); res.redirect('/invoices?error=1'); } else { // For now: log the output file path console.log(`PDF generated and saved to ${outputFolder}${req.params['id']}.pdf`); res.redirect('/invoices?success=1'); } }); }); Before running this code, please ensure that you update the variable to reflect the correct path to your executable. htmlToPdfPath htmltopdf To send an email reminder for an invoice, please go back to your list of invoices and click on “Email Reminder” for any specific invoice. This action will trigger the Node app to call the executable. The executable, in turn, will convert the invoice from the HTML document served by Express into a PDF file. You can locate the resulting PDF file in the directory of your web application. htmltopdf invoices/ Now that you have the ability to generate PDF Invoices, the final step is to send these invoices to your customers. Sending Emails with Nodemailer offers a convenient interface that allows you to access various email transport layers. SMTP is one of the most commonly used options, but you can also utilize services like Amazon SES or your server’s command as alternatives. Nodemailer sendmail To test Nodemailer, you can utilize the , which allows you to log the message to your console. To set up your message and send it using Nodemailer, add the following code snippet just below the “PDF generated and saved to…” statement in your route: stream transport’s JSON option console.log /invoices/:id/email ... // Construct the message const message = { from: 'accounting@example.com', to: invoice.contact_email, subject: 'Reminder: Your Invoice from Tiller, Inc. is Due', html: `<p>Hey ${invoice.contact_name},</p><p>I just wanted to remind you that your invoice for last month's services is now due. I've attached it here for your convenience.</p><p>Thanks for your business!</p>`, attachments: [ { filename: 'invoice.pdf', path: `${outputFolder}${req.params['id']}.pdf`, } ] }; // Use mailer to send invoice nodemailer .createTransport({jsonTransport: true}) .sendMail(message, function (err, info) { if (err) { res.redirect('/invoices?error=1'); } else { console.log(info.message); res.redirect('/invoices?success=1'); } }); ... Please refresh your Node application and click on “Email Reminder” for any of the invoices. This time, you will observe the complete email data object displayed as JSON in your console. { "from": { "address": "accounting@example.com", "name": "" }, "to": [ { "address": "jpretious1@example.com", "name": "" } ], "subject": "Reminder: Your Invoice from Tiller, Inc. is Due", "html": "<p>Hey Junia Pretious,</p><p>I just wanted to remind you that your invoice for last month's services is now due. I've attached it here for your convenience.</p><p>Thanks for your business!</p>", "attachments": [ { "content": "JVBERi0xLjMKJcTl8uXrp...", "filename": "invoice.pdf", "contentType": "application/pdf", "encoding": "base64" } ], "headers": {}, "messageId": "<65ea9109-8d5a-295e-9295-8e98e1b2c667@example.com>" } The string represents the encoded PDF file. For the sake of brevity, I have truncated it in the above example. attachments.content To test the email using a real , you can use . Assuming you have an account with Mailtrap, replace the call with the following code snippet: SMTP server Mailtrap createTransport({jsonTransport: true}) createTransport({ host: "smtp.mailtrap.io", port: 2525, auth: { user: "<YOUR_MAILTRAP_USERID>", pass: "<YOUR_MAILTRAP_PASS>" } }) Upon emailing the Invoice, Mailtrap will capture the output and provide you with the option to download the PDF attachment. If you access your Mailtrap account, you will find an email similar to the example below: Once you’re ready to deploy your app to production, replace the Mailtrap SMTP credentials with a production mail server. Our web application now offers the capability to generate and automatically send PDF Invoices to clients upon request from our billing team. If you require a solution for presenting Invoices online and sending them as PDFs, our application provides a reliable foundation. While Foxit’s HTML to PDF tool is a convenient and efficient option for generating PDFs, it’s important to note that they offer various other solutions as well. With their , Foxit stands out as the ideal choice when integrating PDF functionality into your web, mobile, or desktop applications. software development kits (SDKs) available for multiple platforms Also published . here