npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

markdown-email

v1.0.1

Published

An easy button for creating HTML emails from Markdown

Downloads

67

Readme

markdown-email

markdown-email is an opinionated library to transform a markdown file as an EJS template into an HTML email, ready to send.

It is designed to be used with nodemailer to send emails, but it can be adapted to be used with any email sending library.

I wrote this because I have had to send a lot of automated emails in my career, and I have found that it is very easy to make mistakes which make each email inconsistent with the next, flag your email as spam or, don't work well with your recipient's email client.

This library is designed to make it easier to send emails that look good, are consistent, and are less likely to be flagged as spam.

This library has been tested against mailtrap.io's email testing feature, and it passes both the HTML check and spam analysis. Of course, how well your email does depends on your template content. Check https://www.caniemail.com/ to see what HTML and CSS features you can use in your email.

Installation

npm install markdown-email

Usage

import {renderEmail} from 'markdown-email';
import {readFileSync} from 'fs';
import { createTransport } from 'nodemailer';

// You want to make all your messages have a consistent look.
// Create a template for your email messages. The message-specific content will 
// be inserted into the start of the <body> tag. This string can contain EJS
// expressions.
const html = readFileSync('path/to/html-template.html', 'utf8').toString();

// You can also include CSS in your template.
// Make sure you check that the CSS properties you use are supported by the email 
// clients you are targeting.
const css = readFileSync('path/to/css.css', 'utf8').toString();

// Read the message template from a Markdown file. This file can contain EJS
// expressions.
const messageTemplate = readFileSync('path/to/template.md', 'utf8').toString();

// this contains all the variables that are needed to render the template.
// Make sure you populate this object with every value needed for the EJS templates,
// or the rendering will fail (better fail here than send out a bad email).
const messageContext = {
    recipientName: 'John Doe',
    message: 'Hello, world!',
    alertDate: new Date(),
    productName: 'Acme Widget'
};

// Render the EJS templates, transform the Markdown to HTML, insert 
// it into the HTML template, and inline the CSS. 
const {subject, message, attachments} = await renderEmail(messageTemplate, messageContext{
    surroundingHtml: html,
    styles: css
});

const transport = createTransport({
    host: 'smtp.example.com',
    port: 587
    // ...
});
await transport.sendMail({
    from: '[email protected]',
    to: '[email protected]',
    subject: subject,
    html: message,
    attachments: attachments
});

See src/test/e2e.mjs for a complete example.

Creating templates

You can use EJS expressions in your templates, including the message template as well as the email HTML. When referencing variables from the provided context, prefix them with $.. For example:

const markdown = `Hello <%= $.name %>, this is a message for you!`;
const context = {name: 'John Doe'};

Template validation at runtime

It is also important that the context object contains every variable that is used in the templates. If a referenced value is not found in the context, the rendering will fail with an error. For example:

const markdown = `Hello <%= $.name %>, this is a message for you!`;
const context = {};
const output = await renderEmail(markdown, context);

Will result in the following error:

    throw new Error(`Missing required property ${name}`);
                      ^

Error: ejs:1
 >> 1| Hello <%= $.name %>, this is a message for you!

Missing required property name

Subject

You can also include the message subject in your template. If you do, it will be templated, extracted, removed from the message, and returned as part of the result. For example:

const markdown = `
% subject Hello <%= $.name %>

This is a message for you!
`;
const context = {name: 'John Doe'};
const output = await renderEmail(markdown, context);
console.log(output.subject); // "Hello John Doe"
console.log(output.message); // "This is a message for you!"

Images

If you include images anywhere in your message (Markdown or HTML), they will be base64-encoded and included as attachments in the result. The img tags will automatically be updated to reference the attachment. For example:

const markdown = `
![My Image](path/to/image.png)
`;
const output = await renderEmail(markdown, {});
console.log(output.message); // "<img src='cid:(some generated id)' alt='My Image'>"
console.log(output.attachments); // [{filename: 'image.png', path: '(some base64 string)', cid: '(some generated id)'}]