loading...
Cover image for Subscribing to Mailchimp using Cloud Functions

Subscribing to Mailchimp using Cloud Functions

deammer profile image Maxime Updated on ・3 min read

Hi, folks!

Here is a quick-and-dirty implementation of an email subscription system. Using a few lines of JavaScript and a serverless provider, I'll show you how to securely connect to Mailchimp's API and allow your users to subscribe to an email list.

Requirements:

  • A place to write frontend code, such as CodePen
  • A GitHub or Microsoft account to log in to Webtask
  • A Mailchimp account with an existing list

Setting up

You'll need 3 things from Mailchimp:

  1. an API key which can be generated by going to Account > Extras > API keys. Check out Mailchimp's documentation if needed.
  2. the id of our list, which can be found in List > Settings > List name and defaults.
  3. the name server where the list is hosted, which can be found in the URL. For instance, the server name for https://us1.admin.mailchimp.com/ is us1.

Building the backend

Let's now head over to Webtask.io. Webtask is a free cloud function hosting service built by Auth0's wonderful developers. On their landing page, hit "Try it now" and sign up with the account of your choice.

Screenshot of Webtask's sign-up screen

Let's create a new function using the "Empty Function" template. Give the function a name and hit "Save" to be taken to the editor.

You'll see the boilerplate below:

/**
* @param context {WebtaskContext}
*/
module.exports = function(context, cb) {
  cb(null, { hello: context.query.name || 'Anonymous' });
};

Let's import Axios in order to run some HTTP requests. Click on the wrench icon and go to NPM Modules. Click "Add Module", look for Axios, and add it to your project.

Video clip of adding a node module in Webtask

You're now ready to communicate with Mailchimp! Here's some code just for you:

const axios = require('axios');

module.exports = function (context, callback) {
  // Fail early if no email was passed
  if (!context.body || !context.body.email) {
    callback('Missing email parameter');
    return;
  }

  const { email } = context.body;

  // Replace the 3 values below with your own
  const regionName = 'us1';
  const apiKey = 'xxxxxxxxxx';
  const listId = 'xxxxxxxxxx';
  const url = `https://${regionName}.api.mailchimp.com/3.0/lists/${listId}/members/`;

  axios
    .post(
      url,
      {
        // Tell Mailchimp to subscribe this email
        status: 'subscribed',
        // Note that Mailchimp takes an email_address field, not just email
        email_address: email,
      },
      {
        headers: {
          Authorization: `apikey ${apiKey}`,
        },
      }
    )
    .then(() => {
      // Things went well
      callback(null, { message: 'Email subscribed!' });
    })
    .catch(error => {
      // Things didn't go well
      callback(error.response.data);
    });
};

You're done! πŸŽ‰

Use a REST client like Postman or Insomnia to query your serverless endpoint. The URL can be copied from the bottom of Webtask's UI.

Screenshot of Insomnia with a successful API response

Building a frontend (optional)

If you'd like to build a frontend for this system, here's a barebones form with an input field and a Submit button.

The URL for the action attribute can be copied from the bottom of the Webtask editor.

<form action="your_webtask_url" method="POST">
    <label for="email">Email</label>
    <input type="email" name="email" placeholder="Enter your email" />
    <button type="submit">Subscribe</button>
</form>

Things I've learned

Webtask

When using what Webtask calls the "full-control" programming model, the context's body isn't parsed.

module.exports = function (context, req, res) {
  // context.body is an empty object
}

To work around that restriction, you'll have set up tasks through your CLI or send a pb=1 token when calling the endpoint. I recommend reading the documentation.

Mailchimp

Mailchimp's API returns a ton of useful information when something goes wrong. That data is nested deeper in the response object than I would expect:

.catch(error => {
  const { data } = error.response;

For example, if you reuse an email that's already in your list, you'll see the data below:

{
  "type": "http://developer.mailchimp.com/documentation/mailchimp/guides/error-glossary/",
  "title": "Member Exists",
  "status": 400,
  "detail": "test@domain.com is already a list member. Use PUT to insert or update list members."
}

Thank you for reading, and please let me know if I said anything dumb or incorrect!

Posted on by:

deammer profile

Maxime

@deammer

Gradient developer and JAMstack advocate πŸ₯‘ http://pronoun.is/he

Discussion

pic
Editor guide