How to send automated email sequences using Node.js and Candymail

The Candymail NPM package allows you to send marketing email sequences directly from your Node.js server from a single JSON file. Think of it as a docker.yaml but for email marketing.

How to send automated email sequences using Node.js and Candymail

Automated email sequences are an incredible marketing tool for any startup. An email inbox is one of the few 1:1 marketing channels at your disposal. Use it well.

The Candymail NPM package allows you to send marketing email sequences directly from your Node.js server from a single JSON file. Think of it as a docker.yaml but for email marketing.

Full docs — https://candymail.saasbase.dev

Let’s say we are building a brand new video editor for the web and looking to delight our new users. We can set up an Onboarding email sequence that welcomes our users and slowly introduces them to the platform.

Let’s get started.

Step 1: Define the Onboarding Email Sequence

Here are 3 emails I would add to my sequence to onboard a new user:

  1. Welcome the user immediately when they sign up
Subject: Welcome to VideoMaker+

Thanks for joining! You’re officially a part of the VideoMaker+ family! Join 100’s of passionate filmmakers like you making a difference in everyday life by making the most wonderful content.

2. 1 day later — Show the user the most basic way to get started with the platform

Subject: How to edit your first video?

Ready to get started? Here’s how you can add subtitles to your first video and add some flair:
1. Record 1-min video of you talking into the camera
2. Import the footage into VideoMaker+ app
3. Click on Effects > Retro
4. Turn on: Automatic Subtitles
5. Export!
And that’s it. You now have a retro-looking video with auto-generated subtitles ready to be shared with the world!

3. 3 days later — Check up on how they’re doing and gather feedback

Subject: A friendly check-in from VideoMaker+

Looks like you’ve been using VideoMaker+ in the last few days — and we love that! I just wanted to quickly check-in and how your experience has been with our service.
1. How did you hear about VideoMaker+?
2. What do you like/dislike about VideoMaker+?
3. What can we do to improve your experience?

Now that we know what the content is going to look like. Let’s create our automation file.

Step 2: Create a new automation file

Candymail uses a single JSON file to describe the automation sequence. The above definition can be encoded into a candymail.automation.json like so,

{
   "workflows":[
      {
         "name":"onboarding",
         "description":"Onboard new VideoMaker+ users",
         "trigger_name":"onboarding",
         "emails":[
            {
               "trigger":"time",
               "sendDelay":1,
               "subject":"Welcome to VideoMaker+",
               "body":"<div style='text-align:left'><p>Thanks for joining!<br/><br/>You're officially a part of the VideoMaker+ family! Join 100's of passionate film makers like you making a difference in everyday life by making the most wonderful content.</p></div>",
               "from":"sender@gmail.com"
            },
            {
               "trigger":"time",
               "sendDelay":24,
               "subject":"How to edit your first video?",
               "body":"<div style='text-align:left'><p>Ready to get started? Here's how you can add subtitles to your first video and add some flair:</p><br/><p>1. Record 1-min video of you talking into the camera<br/> 2. Import the footage into VideoMaker+ app<br/> 3. Click on Effects &gt; Retro<br/> 4. Turn on: Automatic Subtitles<br/> 5. Export!</p><br/><p>And that's it. You now have a retro looking video with auto-generated subtitles ready to be shared with the world!</p></div>",
               "from":"sender@gmail.com"
            },
            {
               "trigger":"time",
               "sendDelay":72,
               "subject":"A friendly check-in from VideoMaker+",
               "body":"<div style='text-align:left'><p>Looks like you've been using VideoMaker+ in the last few days - and we love that! I just wanted to quickly check-in and how your experience has been with the app.</p><br/><p>1. How did you hear about VideoMaker+?<br/>2. What do you like/dislike about VideoMaker+?<br/>3. What can we do to improve your experience?</p></div>",
               "from":"sender@gmail.com"
            }
         ]
      }
   ]
}

Note: Remember to change the sender@gmail.com to your own sender email address.

Step 3: Set up a basic Express Server

Create a new folder.

Let’s initialize our project by creating a package.json

npm init -y

Install dependencies with a quick,

npm install express

Add another file named app.js

const express = require('express');
const port = 3000;
const app = express();
app.get('/', async function(req, res, next) {
    res.send('Hello World!')
});
app.listen(port, () => console.log(`Listening on port ${port}!`);)

We can now run our simple server by running,

npm start

Our application should be live at http://localhost:4242.

Step 4: Install Candymail

Import the candymail.automation.file to the root level of the project directory.

Let’s install Candymail by running,

npm install --save candymail

In app.js,

require('dotenv').config();
const candymail = require('candymail');
const express = require('express');
const app = express();
const port = 3000;
const automation = require('./candymail.automation.json') candymail.init(automation.workflows, {
    mail: {
        host: 'smtp.gmail.com',
        port: 465,
        secure: true,
        auth: {
            user: process.env.MAIL_USER,
            pass: process.env.MAIL_PASSWORD,
        },
        tls: {
            rejectUnauthorized: true,
        },
    },
    hosting: {
        url: process.env.HOSTING_URL
    },
    db: {
        reset: true
    },
    debug: {
        trace: true
    },
}).then((e) => {
    candymail.start();
    app.get('/', async (req, res) => {
        res.send('Go to /start to trigger the first workflow');
    });
    app.listen(port, () => {
        console.log(`Learn about our new features at http://localhost:${port}`)
    });
})

Step 5: Add env vars

Create a file at root called .env

MAIL_USER=email@gmail.com
MAIL_PASSWORD=password
RECIPIENT_EMAIL=user@gmail.com
HOSTING_URL=http://localhost:3000
Using Gmail to send emails in Production is not recommended. Use a transactional email service like Mailgun.

Step 6: Set up a "Sign up" endpoint

Let’s set up an /signup endpoint to capture when a user successfully signs up.

app.post('/signup', (req, res) => {
    const user = process.env.RECIPIENT_EMAIL;
    candymail.runWorkflow('onboarding', user);
    res.send('onboarding started');
})

Perfect! Now when the user abc@gmail.com signs up, they will receive a sequence of 3 emails as part of the onboarding process.

But what if the user doesn't want to not receive the emails anymore? Fear not, every email is sent out with an Unsubscribe link in the footer that makes a GET request to the /unsubscribe endpoint on your hosting server.

Step 7: Set up Unsubscribe

app.get('/unsubscribe', (req, res) => {
    const {
        email
    } = req.query;
    
    candymail.unsubscribeUser(email);
    res.send(`Sent an unsubscribe request for ${email}`);
})

Step 8: Test it out

npm start

Let’s fire up Postman and make a POST request to /signup . This will start the automation sequence - Onboarding. We are also printing out the scheduled messages to be sent out at what time. Notice that the time listed is in UTC.

We should expect 3 emails to be sent — 1 at the top of the next hour, the next one in 24 hours, and the one after that in 72 hours.

Here’s the first email I received in my inbox.

Every email comes with an unsubscribe link that the user can click on and they will stop getting future communications.