DEV Community

balavishnuvj
balavishnuvj

Posted on

How to send dynamically created PDF as attachment with Amazon SES on Node JS

To send an email with dynamically created PDF as an attachment. There are two steps.

Step 1: Dynamically create a pdf
Step 2: Send this pdf as an attachment

Libraries used.

npm install aws-sdk ejs nodemailer html-pdf

Why do we need all these libraries?

aws-sdk is used for sending the email.
nodemailer is used to create an email with an attachment.
ejs is the templating engine used for create dynamic HTML.
html-pdf is used to convert HTML to pdf.

Step 1: Dynamically create a pdf

Let us create a template for html.

<!-- template.ejs --!>

<!DOCTYPE html>

<html>
  <head>
    <title>My Table</title>
  </head>
  <body>
    <h1>Table</h1>
    <table style="width: 100%;">
      <tr>
        <th>Qty.</th>
        <th>Unit Price</th>
        <th>Total Cost</th>
      </tr>
      <% if (products.length) { %>
      <tr>
        <% products.forEach(function (product) { %>
        <td id="quantity"><%= product.quantity %></td>
        <td id="unitPrice"><%= product.unitPrice %></td>
        <td id="totalPrice"><%= product.totalPrice %></td>
        <% }) %>
      </tr>
      <% } %>
    </table>
  </body>
</html>

Now let's use this template to generate the HTML. I'm not writing the file to disk. Instead, keep the file in memory and pass it on.

import ejs from 'ejs';
import htmlPdf from 'html-pdf';

export async function htmlToPdfBuffer(pathname, params) {
  const html = await ejs.renderFile(pathname, params);
  return new Promise((resolve, reject) => {
    htmlPdf.create(html).toBuffer((err, buffer) => {
      if (err) {
        reject(err);
      } else {
        resolve(buffer);
      }
    });
  });
}

Usage would be like

const fileBuffer = await htmlToPdfBuffer('template.ejs', {
  products: [{ quantity: 2, unitPrice: 10, totalPrice: 20 }]
});

Now, fileBuffer is the dynamic pdf file which has to be sent. You could use toFile method of html-pdf to write this to disk.

Step 2: Send this pdf as an attachment

We could use aws-sdk directly for attachments. You would have to do MIME encoding manually, which is a bit tedious.

export function sendEmailWithAttachments(
  subject,
  html,
  toAddresses,
  attachments
) {
  const ses = new AWS.SES();
  const transporter = nodemailer.createTransport({
    SES: ses
  });
  const mailOptions = {
    from: "from@example.com",
    subject,
    html,
    to: toAddresses,
    attachments
  };
  transporter.sendMail(mailOptions, (err, data) => {

  });
}

Final usage

const fileBuffer = await htmlToPdfBuffer("template.ejs", {
  products: [{ quantity: 2, unitPrice: 10, totalPrice: 20 }]
});

sendEmailWithAttachments(
  "This is test subject",
  "<p>This email contails attachment</p>",
  ["to@example.com"],
  { filename: "attachment.pdf", content: fileBuffer }
);

Top comments (0)