Using XMLHttpRequest to send a Mailchimp API request in my React Typescript App so users subscribe to the newsletter

Viewed 90

I want to use Mailchimp API in my website so users can enter their email in a field and subscribe to a newsletter. I do not want to use any libraries.

I created a simple form for now with an email field and subscribe button for testing purposes and tried to achieve my goal with XMLHttpRequest. However it does not work, and I am not sure whats wrong or if I need another approach? Is my code structure for the API request correct? I created a Codesandbox with the code. If needed I can paste it also here.

2 Answers

It's a back end only API.

You're not supposed to ship this API key with your JavaScript application. It's intended for back end use only, where you can keep the key private.

Probably the issue described in no more detail than "it does not work", is because Mailchimp will block the request if you try to use the key from a browser. Their documentation describes in detail.

Because of the potential security risks associated with exposing account API keys, Mailchimp does not support client-side implementation of our API using CORS requests or including API keys in mobile apps.

If you still want to use the API for this, you'll have to set up your own back end service which receives the data from the front end of your site and forwards it to Mailchimp.

For example, if your website uses PHP, you could preserve your form's JS code, but point it to your own custom endpoint / PHP file instead.

Mailchimp has a PHP client library you could use to make crafting the HTTP request more robust and less verbose. But you could also do it "manually" if you also don't want to install a PHP library.

// form-submission.php
function read_key() {
    // Could also come from other source, like environment variables.
    // As long as it's in a safe place and can't be leaked.
    return file_get_contents(SECRET_KEY_LOCATION);
}
$apiKey = read_key();
require_once('/path/to/MailchimpMarketing/vendor/autoload.php');

$mailchimp = new MailchimpMarketing\ApiClient();

$mailchimp->setConfig([
    'apiKey' => $api_key,
    'server' => 'YOUR_SERVER_PREFIX'
]);

$response = $mailchimp->lists->addListMember( /* ... form data */);
print_r($response);

Depending on your use case you may need to use one of the many other API endpoints.

The issue is the onSubmit() callback on your "form" element is never executed. In order for the onSubmit() callback on your form to be called upon clicking the "Subscribe" button, the button needs to have a type="submit" attribute on it.

i.e.,

const handleSubmit = () => { ... }

return (
   ...
    <Box 
      onSubmit={handleSubmit}
    >
      <TextField ... />

      <Button
        type="submit"  <-- Add this in order to call onSubmit() upon click
      >
        Subscribe
      </Button>
    </Box>
   ...

Edit:

OP is using the MailChimp API from the client. The MailChimp API will not work on the client side. You can only use the MailChimp API on the server side.

However, you can utilize MailChimp's embedded form action URL to subscribe to user's emails on the client side (in a React component). You can avoid the user from being forwarded to MailChimp by sending a fetch POST request with the embedded form action URL.

This below example may need some tweaking, but this is the general idea on how this can be accomplished.

function handleSubmit(event) {
    event.preventDefault();

    // fetch URL is from MailChimp embedded form action url.
    fetch('http://mailchimp.us8.list-manage.com/subscribe/post', {
        method: 'POST',
        // Not sure if MailChimp used urlencoded or json. You can modify this request to use either.
        headers:{
          'Content-Type': 'application/x-www-form-urlencoded'
        },    
        body: new URLSearchParams({
            'u': 'a123cd45678ef90g7h1j7k9lm',  <-- found in embedded form code.
            'id': 'ab2c468d10',  <-- found in embedded form code.
            'MERGE0': email,  <-- email to be subscribed.
    })
    });
}
Related