Skip to content

Instantly share code, notes, and snippets.

Last active April 8, 2023 10:08
  • Star 11 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
Star You must be signed in to star a gist
What would you like to do?
Progressive mailchimp subscription on Netlify
import { parse } from 'querystring'
const axios = require('axios');
const mailChimpAPI = process.env.MAILCHIMP_API_KEY;
const mailChimpListID = process.env.MAILCHIMP_LIST_ID;
exports.handler = (event, context, callback) => {
let body = {}
try {
body = JSON.parse(event.body)
} catch (e) {
body = parse(event.body)
if (! {
console.log('missing email')
return callback(null, {
statusCode: 400,
body: JSON.stringify({
error: 'missing email'
if (!mailChimpAPI) {
console.log('missing mailChimpAPI key')
return callback(null, {
statusCode: 400,
body: JSON.stringify({
error: 'missing mailChimpAPI key'
if (!mailChimpListID) {
console.log('missing mailChimpListID key')
return callback(null, {
statusCode: 400,
body: JSON.stringify({
error: 'missing mailChimpListID key'
const data = {
status: "pending",
merge_fields: {}
const subscriber = JSON.stringify(data);
console.log("Sending data to mailchimp", subscriber);
// Subscribe an email
method: 'post',
url: `${mailChimpListID}/members/`, //change region (us19) based on last values of ListId.
data: subscriber,
auth: {
username: 'apikey', // any value will work
password: mailChimpAPI
console.log(`status:${response.status}` )
console.log(`data:${}` )
console.log(`headers:${response.headers}` )
if (response.headers['content-type'] === 'application/x-www-form-urlencoded') {
// Do redirect for non JS enabled browsers
return callback(null, {
statusCode: 302,
headers: {
Location: '/thanks.html',
'Cache-Control': 'no-cache',
body: JSON.stringify({})
// Return data to AJAX request
return callback(null, {
statusCode: 200,
body: JSON.stringify({ emailAdded: true })
}).catch(function(error) {
if (error.response) {
// The request was made and the server responded with a status code
// that falls out of the range of 2xx
} else if (error.request) {
// The request was made but no response was received
} else {
// Something happened in setting up the request that triggered an Error
console.log('Error', error.message);
"scripts": {
"start": "netlify-lambda serve source/lambda",
"build": "netlify-lambda build source/lambda"
"dependencies": {
"axios": "^0.19.0",
"dotenv": "^8.1.0",
"netlify-lambda": "^1.6.3"
<div id="message"></div>
<form id="newsletter" class="subscribe" action="/.netlify/functions/form-handler" method="post">
<input type="email" id="inputEmail" name='email' placeholder="Enter email to subscribe for FREE" class="email" required autofocus>
<button class="button" type="submit">Subscribe</button>
var form = document.getElementById('newsletter');
form.addEventListener("submit", function(e) {
email = document.getElementById('inputEmail').value;
function submitEmail(email) {
fetch('/.netlify/functions/form-handler', {
method: 'post',
body: JSON.stringify({
email: email
}).then(function(response) {
return response.json();
}).then(function(data) {
console.log('data from function', data);
messageDiv = document.getElementById('message');
messageDiv.innerText = 'Confirmation email has been sent!'
Copy link

skatkov commented Sep 22, 2019

This function was open source from project.
To find more details on this code and our porject -- read up community post

Thanks for your interest!

Copy link

I'm trying to deploy this on Netlify and running into an error: "SyntaxError: Cannot use import statement outside a module" with the form-handler.js. From what I understand this means that my build is not transpiled using netlify-lambda.

What does your netlify.toml look like for this gist?

Copy link

sgnl commented Dec 22, 2021

@dejardine changing it to const { parse } = require('querystring'); should work without having to transpile the code

Copy link

This is great! Thanks! I wonder how you would go about handling errors?

Currently, when submitting or an already subscribed email address I get this in the browser console:

POST http://localhost:8888/.netlify/functions/form-handler 500 (Internal Server Error)
VM4085:1 Uncaught (in promise) SyntaxError: Unexpected token T in JSON at position 0

And, a timeout when viewing the logs when netlify dev is running: Task timed out after 10.00 seconds

Copy link

paulrudy commented Sep 21, 2022

Thank you for the tutorial and this code, it's been really helpful.

I don't know if something has changed since you wrote it, or if it has to do with my setup (using Astro and netlify), but the test for disabled javascript: if (response.headers['content-type'] === 'application/x-www-form-urlencoded') { ... } isn't working for me. I tried a lot of combinations, but with javascript disabled in the browser, response.headers always had a content-type of application/json, same as when javascript was enabled.

In order to distinguish form data submitted by ajax, I had the javascript add a field to the form data:

body: JSON.stringify({
          email: email,
          "js-submit": true, // form-handler.js can use this to determine whether to return a 302 redirect or a 200

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment