Mailjet is an email delivery service. In this post I will show how we can use this platform to deliver programatically generated PDFs via email. To achieve that we’re going to use Node.js together with following libraries:
- node-mailjet – as a wrapper over the Mailjet API
- pdfkit – to generate PDF files
- base64-stream – to convert generated PDF into a Base64 string which is required by Mailjet
First let’s write a function to generate a Base64 encoded PDF file using PDFKit.
import PDFDocument from "pdfkit";
import { Base64Encode } from "base64-stream";
async function generatePdf(userName: string): Promise<string> {
// we wrap everything with a Promise to make a nice interface
// to just await a PDF content
return new Promise((resolve, reject) => {
console.time("pdf"); // we can track how long it took to generate a PDF
const doc = new PDFDocument();
const stream = doc.pipe(new Base64Encode());
let finalString = ""; // we collect the actual stream data in this variable
doc
.fontSize(24) // we can configure different font size for the first line
.text("Order confirmation")
.lineGap(1)
.fontSize(16)
.text(`Hello ${userName}. We just received your order`)
.end(); // this will trigger the "end" event on the stream
stream.on("data", (chunk) => {
finalString += chunk;
});
stream.on("end", () => {
console.timeEnd("pdf"); // on my machine it took 32ms
resolve(finalString);
});
stream.on("error", (err) => {
reject(err);
});
});
}
The result is going to look something like this:
JVBERi0xLjMKJf////8KNyAwIG9iago8PAovVHlwZSAvUGFnZQovUGFyZW50IDEgMCBSCi9NZWRpYUJveCBbMCAwIDYxMiA3OTJdCi9Db250ZW50cyA1IDAgUgovUmVzb3VyY2VzIDYgMCBSCj4+CmVuZG9iago2IDAgb2JqCjw8Ci9Qcm9jU2V0IFsvUERGIC9UZXh0IC9JbWFnZUIgL0ltYWdlQyAvSW1hZ2VJXQovRm9udCA8PAovRjEgOCAwIFIKPj4KPj4KZW5kb2JqCjUgMCBvYmoKPDwKL0xlbmd0aCAxODQKL0ZpbHRlciAvRmxhdGVEZWNvZGUKPj4Kc3RyZWFtCnicjY+xDsIwDET3fIV/AHDc+NxKVQYkGNiQsiGGqjRbB/5/wYUKgViQpZxzsXLPkdhrE/2wTmicwz3EH29fVjOSCRnL1tBSmcPuGEkSlRoufaomSFATYTSomAB0Jpk2otTjhmgJ3fKQia9UTuFQwvmPQLT8GRixBrZQjF5VOA3+b4vJu+SdZoqeKZ4EduVMyVUtU+MKdcTB1BpLwo6tDqwOi0xPVsXid35bpqu9lnov+MX/ADwdQ6AKZW5kc3RyZWFtCmVuZG9iagoxMCAwIG9iagooUERGS2l0KQplbmRvYmoKMTEgMCBvYmoKKFBERktpdCkKZW5kb2JqCjEyIDAgb2JqCihEOjIwMjIwODEyMTEyNDQ2WikKZW5kb2JqCjkgMCBvYmoKPDwKL1Byb2R1Y2VyIDEwIDAgUgovQ3JlYXRvciAxMSAwIFIKL0NyZWF0aW9uRGF0ZSAxMiAwIFIKPj4KZW5kb2JqCjggMCBvYmoKPDwKL1R5cGUgL0ZvbnQKL0Jhc2VGb250IC9IZWx2ZXRpY2EKL1N1YnR5cGUgL1R5cGUxCi9FbmNvZGluZyAvV2luQW5zaUVuY29kaW5nCj4+CmVuZG9iago0IDAgb2JqCjw8Cj4+CmVuZG9iagozIDAgb2JqCjw8Ci9UeXBlIC9DYXRhbG9nCi9QYWdlcyAxIDAgUgovTmFtZXMgMiAwIFIKPj4KZW5kb2JqCjEgMCBvYmoKPDwKL1R5cGUgL1BhZ2VzCi9Db3VudCAxCi9LaWRzIFs3IDAgUl0KPj4KZW5kb2JqCjIgMCBvYmoKPDwKL0Rlc3RzIDw8CiAgL05hbWVzIFsKXQo+Pgo+PgplbmRvYmoKeHJlZgowIDEzCjAwMDAwMDAwMDAgNjU1MzUgZiAKMDAwMDAwMDgwNSAwMDAwMCBuIAowMDAwMDAwODYyIDAwMDAwIG4gCjAwMDAwMDA3NDMgMDAwMDAgbiAKMDAwMDAwMDcyMiAwMDAwMCBuIAowMDAwMDAwMjA4IDAwMDAwIG4gCjAwMDAwMDAxMTkgMDAwMDAgbiAKMDAwMDAwMDAxNSAwMDAwMCBuIAowMDAwMDAwNjI1IDAwMDAwIG4gCjAwMDAwMDA1NTAgMDAwMDAgbiAKMDAwMDAwMDQ2NCAwMDAwMCBuIAowMDAwMDAwNDg5IDAwMDAwIG4gCjAwMDAwMDA1MTQgMDAwMDAgbiAKdHJhaWxlcgo8PAovU2l6ZSAxMwovUm9vdCAzIDAgUgovSW5mbyA5IDAgUgovSUQgWzwxMWI2ZjBkMGUzYWY2ZmNhNGQ0NTc5Y2RjZTMyZWNhYj4gPDExYjZmMGQwZTNhZjZmY2E0ZDQ1NzljZGNlMzJlY2FiPl0KPj4Kc3RhcnR4cmVmCjkwOQolJUVPRgo=
Now that we have a function to generate a PDF we can use Mailjet API to send the email:
import Mailjet from "node-mailjet";
// ...
async function main(sendToEmail: string, sendToName: string) {
const apiKey = process.env.MAILJET_API_KEY as string;
const apiSecret = process.env.MAILJET_API_SECRET as string;
const mailjet = Mailjet.apiConnect(apiKey, apiSecret);
const pdfContent = await generatePdf("John Doe");
await mailjet.post("send", { version: "v3.1" }).request({
Messages: [
{
From: {
Email: "delivery.system@yourcompany.com",
Name: "Delivery",
},
To: [
{
Email: sendToEmail,
Name: sendToName,
},
],
Subject: "Order confirmation",
TextPart:
"Dear receiver. Here's a confirmation or your order",
Attachments: [
{
ContentType: "application/pdf",
FileName: "confirmation.pdf",
Base64Content: pdfContent,
},
],
},
],
});
}
And if we call the function and check our email we can see the email looks like on the screenshots below: