Node

How to Integrate MailChimp with your NodeJS app

How to Integrate MailChimp with your NodeJS app

This post was originally published on Codementor.io

MailChimp is a well-known email marketing SaaS product. With its generous free tier option, it’s seen as the perfect solution for many startups and small businesses who want to set up and build u their mailing lists.

But what many fail to notice is how rich it’s REST API is.

That’s why in this tutorial, I’d like to walk you through a few use
cases for how you may want to integrate MailChimp into your own Node.JS application, focusing on:

  1. Adding new users to your own mailing list in MailChimp.
  2. Allowing users to import an existing list of contacts from their MailChimp account into your application and sync them back.

We’ll be using the following Node.js libraries:
Express for our backend
Superagent to make REST requests to MailChimp
– A few other small libraries for performing OAuth

1 – Adding new users to MailChimp

First let’s start by setting up a very simple project on the command line:

$ npm init // feel free to enter whatever for these
$ npm install --save express body-parser superagent
$ touch index.js

This will install our core dependencies and create our launch file. Open index.js in your text editor of choice and paste the following:

var express = require('express');
var bodyParser = require('body-parser');
var app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: true}));

app.get('/', function (req, res) {
  res.send('Hello World!');
});

app.listen(3000, function () {
  console.log('Example app listening on port 3000!');
});

Then on the command line type:

$ node index.js
Example app listening on port 3000!

If you go into your browser to http://localhost:3000/, you should see a simple page which says “Hello World!”. With that set up, we can now start integrating a bit deeper.

Adding a signup form

We’ll create a very simple HTML page in views/signup.html which takes the first name, last name, and email address:

<!doctype html>
<html>
    <head>
        <title>Sign Up</title>
        <link href="https://cdnjs.cloudflare.com/ajax/libs/spectre.css/0.1.25/spectre.min.css" rel="stylesheet" crossorigin="anonymous">
    </head>
    <body>
        <form action="/signup" method="POST" class="centered mt-10 ml-10 mr-10">
            <div class="form-group">
                <label class="form-label" for="firstname">First Name</label>
                <input class="form-input" type="text" name="firstname" id="firstname"/>
            </div>
            <div class="form-group">
                <label class="form-label" for="lastname">Last Name</label>
                <input class="form-input" type="text" name="lastname" id="lastname"/>
            </div>
            <div class="form-group">
                <label class="form-label" for="email">Email</label>
                <input class="form-input" type="text" name="email" id="email"/>
            </div>
            <input type="submit" class="btn btn-primary" value="Submit"/>
        </form>
    </body>
</html>

In our index.js we need to serve up static files, so please add the following line:

app.use(express.static('views'));

We also want to handle the form submission; so for now add the following to index.js

app.post('/signup', function (req, res) {
  // save user details to your database.
  res.send('Signed Up!');
});

Now when you re-run the app and signup, you should see the following:

Our Sign Up Page

Saving our new user to MailChimp

I’m going to assume you have a database somewhere to save this user to, so let’s skip straight to saving this user to a new list in MailChimp.

We’ll need the following information from MailChimp to make the calls:

  • Your API token – Log in to your MailChimp account and go to Profile in the top right. Then on the Profile page go to Extras -> API Keys. Scroll down and if you don’t have any available then click Create A Key:Generate MailChimp API Key
  • Your Server Instance – This is also embedded in your API token. It is taken from the last characters after the -. For example my API token is 637274b5ab272affbf7df7d3723ea2a1-us6, therefore my server instance is us6.
  • The Unique List Id – this is for the list you want to add people to. For this, click on Lists, find your list, then on the right hand side click the dropdown arrow, then choose Settings and scroll down on this page to the bottom where you should see Unique id for list <your list name>:Get List Unique ID

With all of these, we’re ready to make some REST calls! I personally prefer using a library called SuperAgent to make rest calls (we installed it with our initial npm modules).

At the top of our index.js load superagent:

var request = require(&#039;superagent&#039;);

Then we’ll update our signup method:

var mailchimpInstance   = &#039;us6&#039;,
    listUniqueId        = &#039;b6a82d89f0&#039;,
    mailchimpApiKey     = &#039;637274b5ab272affbf7df7d3723ea2a1-us6&#039;;

app.post(&#039;/signup&#039;, function (req, res) {
    request
        .post(&#039;https://&#039; + mailchimpInstance + &#039;.api.mailchimp.com/3.0/lists/&#039; + listUniqueId + &#039;/members/&#039;)
        .set(&#039;Content-Type&#039;, &#039;application/json;charset=utf-8&#039;)
        .set(&#039;Authorization&#039;, &#039;Basic &#039; + new Buffer(&#039;any:&#039; + mailchimpApiKey ).toString(&#039;base64&#039;))
        .send({
          &#039;email_address&#039;: req.body.email,
          &#039;status&#039;: &#039;subscribed&#039;,
          &#039;merge_fields&#039;: {
            &#039;FNAME&#039;: req.body.firstName,
            &#039;LNAME&#039;: req.body.lastName
          }
        })
            .end(function(err, response) {
              if (response.status &lt; 300 || (response.status === 400 &amp;&amp; response.body.title === &quot;Member Exists&quot;)) {
                res.send(&#039;Signed Up!&#039;);
              } else {
                res.send(&#039;Sign Up Failed :(&#039;);
              }
          });
});

Here we’ve added variables for our three important pieces of information: MailChimp instance, unique list ID, and our API key. Then in our post handler, we’re making a POST request to the MailChimp list management REST API. We set the following HTTP Headers:

  • Content-Type – to be JSON and utf-8 characters
  • Authorization – we base64 encode our MailChimp API key and pass it as the Basic auth token.

Next we send the data for the new contact we want to add, including:

  • Their email address;
  • What we want their status to be on the mailing list. This can be one-off: subscribed, unsubscribed, pending, and cleaned; and
  • The values we want to set for the merge_fields on this list. Merge fields allow you to add extra data to a contact in a mailing list. For example you could store phone numbers, dates of births, company names, etc. In this example we’ll just add the first name and last name

Finally we listen for the response by registering an end handler. In here we check for two states initially. If the status is less than 300 it means the user was successfully added, or if we get back a HTTP status 400 but the title in the response says Member Exists, then the email address is already in this list. In both cases we can report back to the user that they have successfully signed up. If we get any other status code then something went wrong. In this situation, you’d likely want to let the user try again or raise an alert to yourself and manually fix it.

Testing Sign Up

And if we go check out our MailChimp list, we should see one new member:

New Member Added To MailChimp

2 – Letting your users integrate with their MailChimp account

Now we’re adding our own users, wouldn’t it be awesome to let our users integrate our app with their MailChimp account? Some common use cases are:

  • Perhaps you want to offer mailing list functionality without writing it yourself—for example if you’re writing a CRM, shopping platform, or a blogging service;
  • Import contacts to pre-fill your users contact list; or to
  • Create and Send campaign emails on their behalf from within your app.

In our example, we take a quick look at how we could import all the contacts from an existing Mailing List in MailChimp into our own data store. We’ll do this in 3 stages:

  1. We’ll use OAuth and let the user grant us access to their MailChimp account
  2. With that authentication granted we’ll grab the available Lists and pick which one they want to sync the members from
  3. We’ll grab all the members and store them!

So let’s get cracking!

Using OAuth to get access to the users account

In order to access another user’s account on MailChimp, we need to register ourselves as an App on the platform:

  • Log in to your MailChimp account and go to Profile on the top right. Then on the Profile page, go to Extras -> Registered apps. Click Register An App. You’ll then be presented with a form to fill in the details of your app:

enter image description here

For the most part you can set these values to whatever makes sense. The really important one though is Redirect URI. This is the url in our application where MailChimp will redirect users once they’ve been authenticated. Since we’re going to run this on our local machine for now, we need to set this to:

http://127.0.0.1:3000/mailchimp/auth/callback

enter image description here

Once you’ve clicked Create App you’ll be told your app is created. On this page, scroll down and you’ll find two very important pieces of information:

  • Client ID
  • Client Secret

enter image description here

Now let’s create a simple page in our views directory which will trigger our flow called integrated-mailchimp.html:

&lt;!doctype html&gt;
&lt;html&gt;
    &lt;head&gt;
        &lt;title&gt;Integrate MailChimp&lt;/title&gt;
        &lt;link href=&quot;https://cdnjs.cloudflare.com/ajax/libs/spectre.css/0.1.25/spectre.min.css&quot; rel=&quot;stylesheet&quot; crossorigin=&quot;anonymous&quot;&gt;
    &lt;/head&gt;
    &lt;body&gt;
        &lt;a class=&quot;btn btn-primary&quot; href=&quot;/mailchimp/auth/authorize&quot;&gt;Connect with MailChimp&lt;/a&gt;
    &lt;/body&gt;
&lt;/html&gt;

Next we need to hook up an express handler to process the call to /mailchimp/auth/authorize:

var querystring = require(&#039;querystring&#039;);
var mailchimpClientId = &#039;xxxxxxxxxxxxxxxx&#039;;

app.get(&#039;/mailchimp/auth/authorize&#039;, function(req, res) {
  res.redirect(&#039;https://login.mailchimp.com/oauth2/authorize?&#039; +
            querystring.stringify({
                &#039;response_type&#039;: &#039;code&#039;,
                &#039;client_id&#039;: mailchimpClientId,
                &#039;redirect_uri&#039;: &#039;http://127.0.0.1:3000/mailchimp/auth/callback&#039;
            }));
});

Insert your MailChimp Client ID from earlier and then restart your server and hit our new page: http://localhost:3000/integrate-mailchimp.html:

enter image description here

If you try it out, you should see that when you click the button you’re asked to log into MailChimp. Then afterwards you’re returned to a page on your local machine —this is perfect. Now we need to handle the OAuth callback from MailChimp.

The OAuth callback needs to do the following:

  • Request an access_token for the user. This is needed to make all future requests for this user
  • Request for the OAuth metadata for the use. This provides information about which API Endpoint we need to talk to for this user
  • Save the above information for the user for future interactions with MailChimp

Let’s see the code for this:

var mailchimpSecretKey = &#039;xxxxxxxxxxxxxxxxxxxx&#039;;
var dataStore = require(&#039;./dataStore.js&#039;);

app.get(&#039;/mailchimp/auth/callback&#039;, function(req, res) {
  request.post(&#039;https://login.mailchimp.com/oauth2/token&#039;)
         .send(querystring.stringify({
            &#039;grant_type&#039;: &#039;authorization_code&#039;,
            &#039;client_id&#039;: mailchimpClientId,
            &#039;client_secret&#039;: mailchimpSecretKey,
            &#039;redirect_uri&#039;: &#039;http://127.0.0.1:3000/mailchimp/auth/callback&#039;,
            &#039;code&#039;: req.query.code
          }))
            .end((err, result) =&gt; {
                if (err) {
                    res.send(&#039;An unexpected error occured while trying to perform MailChimp oAuth&#039;);
                } else {
                  // we need to get the metadata for the user
                  request.get(&#039;https://login.mailchimp.com/oauth2/metadata&#039;)
                    .set(&#039;Accept&#039;, &#039;application/json&#039;)
                    .set(&#039;Authorization&#039;, &#039;OAuth &#039; + result.body.access_token)
                        .end((err, metaResult) =&gt; {
                            if (err) {
                                res.send(&#039;An unexpected error occured while trying to get MailChimp meta oAuth&#039;);
                            } else {
                                // save the result.body.access_token
                                // save the metadata in metaResult.body
                                // against the current user
                                var mailchimpConf = metaResult;
                                mailchimpConf.access_token = result.body.access_token;
                                dataStore.saveMailChimpForUser(mailchimpConf.login.email, metaResult);
                                res.redirect(&#039;/pick-a-list.html?email=&#039; + mailchimpConf.login.email)
                            }
                        });
                }
            });
});

To remind ourselves, the above handler will get called after the user has logged into MailChimp for us, and we’re given a temporary code with which we can request the long-lived access_token. Once we get the access_token, we immediately make a second REST call to get our user’s metadata. The metadata returned looks like:

{
"dc": "us6",
"role": "owner",
"accountname": "mattgoldspink",
"user_id": 15048915,
"login": {
"email": "mattgoldspink1@gmail.com",
"avatar": null,
"login_id": 15048915,
"login_name": "mattgoldspink",
"login_email": "mattgoldspink1@gmail.com"
},
"login_url": "https://login.mailchimp.com",
"api_endpoint": "https://us6.api.mailchimp.com"
}

In the above JSON response, the most important piece of information is the api_endpoint. All future REST requests for this user to MailChimp must be made to this server.

For simplicity, I’ve created a very simple in memory dataStore.js file which looks like:

var simpleInMemoryDataStore = {
    mailchimpConf: {}
};

module.exports = {
    saveMailChimpForUser: function(email, mailchimpConf) {
        simpleInMemoryDataStore.mailchimpConf[email] = mailchimpConf;
    },
    getMailChimpForUser: function(email) {
        return simpleInMemoryDataStore.mailchimpConf[email];
    }
};

I shall leave the real exercise of saving this information and the access_token as an exercise for the reader since everyone’s data storage solution is different.

Getting the user’s lists

Now we can start building a simple UI which lets the user select their List and then imports the Members. After connecting to MailChimp, we redirect the user to the pick-a-list.html page.

Let’s write this page:

&lt;!doctype html&gt;
&lt;html&gt;
    &lt;head&gt;
        &lt;title&gt;Pick A List From MailChimp&lt;/title&gt;
        &lt;link href=&quot;https://cdnjs.cloudflare.com/ajax/libs/spectre.css/0.1.25/spectre.min.css&quot; rel=&quot;stylesheet&quot; crossorigin=&quot;anonymous&quot;&gt;
    &lt;/head&gt;
    &lt;body&gt;
        &lt;h1&gt;Pick a List&lt;/h1&gt;
        &lt;p&gt;Choose which list to sync your Members from:
            &lt;select id=&quot;lists&quot;&gt;
                &lt;option value=&quot;null&quot;&gt;&lt;/option&gt;
            &lt;/select&gt;
        &lt;/p&gt;
        &lt;script src=&quot;https://code.jquery.com/jquery-2.2.4.min.js&quot;&gt;&lt;/script&gt;
        &lt;script&gt;
            $(function() {
                var queryParams = new URLSearchParams(location.search.slice(1));
                var mailingListSelect = $(&#039;#lists&#039;);
                // 1. make AJAX call for the list of Lists
                $.get(&#039;/mailchimp/lists?email=&#039; + queryParams.get(&#039;email&#039;), function(data) {
                    // 2. insert lists into DOM
                   data.forEach(function(mailchimpList) {
                        mailingListSelect.append(&#039;&lt;option value=&quot;&#039; + mailchimpList.id + &#039;&quot;&gt;&#039;+ mailchimpList.name + &#039;(&#039; + mailchimpList.stats.member_count  + &#039; Members)&#039; + &#039;&lt;/option&gt;&#039;);
                    });
                });
            });
        &lt;/script&gt;
    &lt;/body&gt;
&lt;/html&gt;

I’ve kept the logic very simple here. When the page loads we get the email address from the url using URLSearchParams. Then we simply perform an ajax request to our backend to get all the mailing lists for the current user. Once that returns, we add them as <option>‘s into our select.

The backend service that powers this looks like:

app.get(&#039;/mailchimp/lists&#039;, function(req, res) {
  var mailchimpConf = dataStore.getMailChimpForUser(req.query.email);
  request.get(mailchimpConf.api_endpoint + &#039;/3.0/lists&#039;)
                .set(&#039;Accept&#039;, &#039;application/json&#039;)
                .set(&#039;Authorization&#039;, &#039;OAuth &#039; + mailchimpConf.access_token)
                    .end((err, result) =&gt; {
                        if (err) {
                            res.status(500).json(err);
                        } else {
                            res.json(result.body.lists);
                        }
                    });
});

We simply retrieve the MailChimp configuration for the user from our dataStore and make a REST request to MailChimp’s list API. Notice that we construct the MailChimp REST API using the api_endpoint we stored for the user. We also have to pass the OAuth access_token for the user in order to authenticate to their account.

If you restart your server and re-authenticate with MailChimp, you should now see the select list in the page populated with your mailing lists!

enter image description here

Getting a list’s members

Now that we have all the user’s Mailing Lists when they choose one, we should go retrieve all the contacts in that list so that we can:

  • display them in the UI
  • sync them to our database for the user.

First, on our client side, we’ll update our pick-a-list.html page by adding:

  • a simple HTML table to show the members
  • and a jQuery handler to listen to the selection change:
        &lt;h2&gt;Members&lt;/h2&gt;
        &lt;table id=&quot;members&quot; class=&quot;table&quot;&gt;
            &lt;thead&gt;
                &lt;th&gt;Email&lt;/th&gt;
                &lt;th&gt;First Name&lt;/th&gt;
                &lt;th&gt;Last Name&lt;/th&gt;
            &lt;/thead&gt;
            &lt;tbody&gt;
            &lt;/tbody&gt;
        &lt;/table&gt;
        &lt;script src=&quot;https://code.jquery.com/jquery-2.2.4.min.js&quot;&gt;&lt;/script&gt;
        &lt;script&gt;
            $(function() {
                var queryParams = new URLSearchParams(location.search.slice(1));
                var mailingListSelect = $(&#039;#lists&#039;);
                // 1. make AJAX call for the list of Lists
                $.get(&#039;/mailchimp/lists?email=&#039; + queryParams.get(&#039;email&#039;),
                    // code from previous step
                );

                mailingListSelect.change(function() {
                    // 3. when an option is select then download the list of members
                    $.get(&#039;/mailchimp/list/members/&#039; + mailingListSelect.val() + &#039;?email=&#039; + queryParams.get(&#039;email&#039;) , function(data) {
                        var tbodyEl = $(&#039;#members tbody&#039;);
                        tbodyEl.html(&#039;&#039;);
                        data.forEach(function(member) {
                            tbodyEl.append(&#039;&lt;tr&gt;&lt;td&gt;&#039; + member.email_address + &#039;&lt;/td&gt;&lt;td&gt;&#039; + member.merge_fields.FNAME + &#039;&lt;/td&gt;&lt;td&gt;&#039; + member.merge_fields.LNAME + &#039;&lt;/td&gt;&lt;/tr&gt;&#039;);
                        });
                    });
                });
            });
        &lt;/script&gt;

So here we added a new part to the page which includes a simple html table to render our members. Then we added our change handler which makes an Ajax request to our backend to get the lists members. On responding, we simply clear the body of the table and add our new members.

Let’s take a look at our backend service for this:

app.get(&#039;/mailchimp/list/members/:id&#039;, function(req, res) {
  var mailchimpConf = dataStore.getMailChimpForUser(req.query.email);
  request.get(mailchimpConf.api_endpoint + &#039;/3.0/lists/&#039; + req.params.id + &#039;/members&#039;)
                .set(&#039;Accept&#039;, &#039;application/json&#039;)
                .set(&#039;Authorization&#039;, &#039;OAuth &#039; + mailchimpConf.access_token)
                    .end((err, result) =&gt; {
                        if (err) {
                            res.status(500).json(err);
                        } else {
                            res.json(result.body.members);
                        }
                    });
});

If you compare this to our earlier call to get the lists, you’ll see it’s almost identical. In fact all future API calls to MailChimp now become very simple!

If you restart your server and try this, then you’ll see the table will now populate once you select a mailing list:

enter image description here

3. Where to go from here?

Now that you have the list of members, you can easily save them to your data store. Each member has an ID which is used to look it up in MailChimp. Therefore if you wanted to sync back changes to that user in MailChimp, you’d simply make an HTTP PATCH call to the members’ endpoint. And in the request body, add these changes:

request.patch(mailchimpConf.api_endpoint + &#039;/3.0/lists/&#039; + req.params.id + &#039;/members/&#039; + req.params.memberId)
                .set(&#039;Accept&#039;, &#039;application/json&#039;)
                .set(&#039;Authorization&#039;, &#039;OAuth &#039; + mailchimpConf.access_token)
                .send({&quot;merge_fields&quot;:{&quot;FNAME&quot;:&quot;new&quot;,&quot;LNAME&quot;:&quot;name&quot;})
                  .end(...)

The MailChimp REST API is extremely rich and supports viewing and editing all sorts of data, including:

  • Adding notes to mailing list members.
  • Create new campaigns.
  • Create and view mail templates.
  • Display reports.
  • Even manage e-commerce stores.

Checkout their API documentation for all the available endpoints you can interact with:

Author: Matt Goldspink

I'm a web developer based in the UK. I'm currently UI Architect at Vlocity, Inc, developing UI's on the Salesforce platform using a mix of Web Components, Angular.js and Lightning.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.