- Joined
- May 7, 2018
- Messages
- 4,575
Thanks to some of the recent threads by @Varun (example 1, example 2), collecting emails in campaigns has become pretty popular here in the forum. That’s great, since it can be one of the best long-term routes you can go if you’re going to do affiliate marketing for longer than the typical 6 months a majority of affiliates last for.
An important thing if you’ve got an email list is that it’s clean. This will ensure you don’t send emails to fake emails, causing bounces that can lead to your ESP account getting banned. There are many routes you can take to do this, such as using Zapier to verify the email after singing up. However, the issue with this is that invalid emails may already have been posted back to your traffic source, which is obviously not ideal.
The better route to go is to verify the email address at the time they submit it, so if it’s invalid the user can fix it. Last week, I shared a post about submitting forms with Javascript, which we’ll be building off in this post to add email verification to the sign up process.
Let’s go!
With Zerobounce, you can verify up to 100 emails for free and then after that each verification will cost at most $0.008. That’s a pretty good deal and it gets even cheaper if you buy 5,000+ pre-paid verification credits at a time. I highly suggest you sign up now, and then wait until they send you a 20%+ discount code via email to make your credit purchase.
After you’ve signed up, sign into your account and:
Next, click + Add Additional API Key:
Save this key somewhere, as we’ll need it later on in this guide.
It’s a serverless function platform (run code on a server without the headaches of managing a server) from Cloudflare that allows anyone to easily run server-side code. Pricing is free for up to 100k requests per day, which is really amazing. It’s also one of the easiest serverless platforms I’ve found so far (plus, it’s only the best thing to happen since sliced bread ).
Once you’re signed up, you should be able to access the service from inside your Cloudflare account:
On the next page:
On the next page you can click the Quick Edit button.
At this point your worker is already deployed on the default workers.dev domain, which you can use, but you can also use a custom domain (if you want). Instructions for setting that up can be found here. It’s a bit more advanced, so the code in this post assumes you didn’t use a custom domain and should still work.
You should now be inside of the web editor:
Here you can write and test your code easily, which is nice if you’re not a full-stack dev as I’m not.
First things first, delete all the code that’s already there. Then, write the event listener to receive the request:
After that we need a function to handle the request:
This function will only handle POST and OPTIONS requests. The POST request will be the data we send to the worker and the OPTIONS request will be for CORS (super annoying, but the code coming up will get around this browser security feature).
If the request is the OPTIONS request automatically done by your browser, we need a function to handle that:
This will set the correct headers to the browser doesn’t have an issue with Cross Origin Resource Sharing.
And now let’s add a function to handle the data we send to the worker:
This function will accept JSON data. If it’s not JSON, the request will be denied. You may notice there are 2 new functions in this code, validateEmail() and postToSendy(), which we’ll also need to write.
First, let’s validate the email. This is super easy because the Zerobounce API is super simple to use (documentation can be found here, if needed):
You’ll need to replace YOUR_API_KEY with your Zerobounce API key we generated earlier.
This function sends the user’s email address to Zerobounce for verification. They will respond with the status. There are actually 7 status’ they can reply with, but to keep this tutorial as simple as possible we’ll only care about a “valid” response. Valid means that Zerobounce considers the user’s email is valid.
Finally, we need to write the function to send the data to the Sendy API. This code can be easily adapted to use any ESP API, such as Aweber.
You’ll want to replace YOUR_SENDY_URL with your actual Sendy URL and YOUR_SENDY_API_KEY with your API key. As with the Zerobounce API key, it’s a wise thing to do to keep the key server-side like we’re doing to protect it.
If you need to reference the Sendy API documentation then you can find it here.
And that’s it for our Cloudflare Worker code. You can concatenate it all and click Save and Deploy in the Cloudflare Worker editor. The URL in the editor is where you’ll want to send the data from your form on your landing page.
In your script.js file on your landing page find the following code:
Where the arrow points, you'll want to insert this line of code:
data.list = params.list;
When you add your landing page to your tracker you'll want to append the Sendy list ID as a URL parameter:
And then the user will be subscribed to that Sendy list when they submit the form.
Next, starting at the script.js comment “// If the data on the form is valid, perform a POST request to my fake API" we need to modify the following:
With these changes the data from your form will be sent to your Cloudflare Worker, the email will be verified with the Zerobounce API, if it passes verification the user will be subscribed to your Sendy list. If the email is not valid the error response from the Sendy API key should display on your form.
Now you can be sure only valid emails are making it onto your email list and being posted back to your traffic source.
An important thing if you’ve got an email list is that it’s clean. This will ensure you don’t send emails to fake emails, causing bounces that can lead to your ESP account getting banned. There are many routes you can take to do this, such as using Zapier to verify the email after singing up. However, the issue with this is that invalid emails may already have been posted back to your traffic source, which is obviously not ideal.
The better route to go is to verify the email address at the time they submit it, so if it’s invalid the user can fix it. Last week, I shared a post about submitting forms with Javascript, which we’ll be building off in this post to add email verification to the sign up process.
Let’s go!
Generate Your Email Verification API Key
To verify the email addresses submit on our landing page we’re going to need to use an email verification service. There are a ton of these available, but my preference is Zerobounce... one of the most popular.With Zerobounce, you can verify up to 100 emails for free and then after that each verification will cost at most $0.008. That’s a pretty good deal and it gets even cheaper if you buy 5,000+ pre-paid verification credits at a time. I highly suggest you sign up now, and then wait until they send you a 20%+ discount code via email to make your credit purchase.
After you’ve signed up, sign into your account and:
- In the left-hand menu, click API - Keys & Info
- Click Your API Key
Next, click + Add Additional API Key:
Save this key somewhere, as we’ll need it later on in this guide.
Note: Keep this key secure, as anyone that knows it can use your credits in your account. That’s why we’re going to secure it server-side with Cloudflare Workers
Build a Cloudflare Worker to Execute the Verification
Now you need to sign up for Cloudflare Workers.It’s a serverless function platform (run code on a server without the headaches of managing a server) from Cloudflare that allows anyone to easily run server-side code. Pricing is free for up to 100k requests per day, which is really amazing. It’s also one of the easiest serverless platforms I’ve found so far (plus, it’s only the best thing to happen since sliced bread ).
Once you’re signed up, you should be able to access the service from inside your Cloudflare account:
- On the left-hand menu, click Workers.
- Click Create a Service.
Note: There may be a few initial account setup steps I’m missing and can no longer see with my account, but from what remember they were very straight forward to follow.
On the next page:
- Type a service name
- Select HTTP handler
- Click Create service
At this point your worker is already deployed on the default workers.dev domain, which you can use, but you can also use a custom domain (if you want). Instructions for setting that up can be found here. It’s a bit more advanced, so the code in this post assumes you didn’t use a custom domain and should still work.
You should now be inside of the web editor:
Here you can write and test your code easily, which is nice if you’re not a full-stack dev as I’m not.
First things first, delete all the code that’s already there. Then, write the event listener to receive the request:
JavaScript:
addEventListener("fetch", event => {
event.respondWith(handle(event.request))
})
After that we need a function to handle the request:
JavaScript:
// Handle the request
async function handle(request) {
if (request.method === 'OPTIONS') {
return handleOptions(request);
} else if (request.method === 'POST') {
return handlePost(request);
} else {
return new Response(null, {
status: 405,
statusText: 'Method Not Allowed',
});
}
}
This function will only handle POST and OPTIONS requests. The POST request will be the data we send to the worker and the OPTIONS request will be for CORS (super annoying, but the code coming up will get around this browser security feature).
If the request is the OPTIONS request automatically done by your browser, we need a function to handle that:
JavaScript:
// CORS headers to remove security errors in the browser
const corsHeaders = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, HEAD, POST, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type',
};
// Handle the Options request to apply the correct headers
function handleOptions(request) {
if (
request.headers.get('Origin') !== null &&
request.headers.get('Access-Control-Request-Method') !== null &&
request.headers.get('Access-Control-Request-Headers') !== null
) {
// Handle CORS pre-flight request.
return new Response(null, {
headers: corsHeaders,
});
} else {
// Handle standard OPTIONS request.
return new Response(null, {
headers: {
Allow: 'GET, HEAD, POST, OPTIONS',
...corsHeaders,
},
});
}
}
This will set the correct headers to the browser doesn’t have an issue with Cross Origin Resource Sharing.
And now let’s add a function to handle the data we send to the worker:
JavaScript:
// Handle the POST request if the content-type is application/json
async function handlePost(request) {
if (request.headers.get('Content-Type') !== 'application/json') {
return new Response(null, {
status: 415,
statusText: 'Unsupported Media Type',
});
}
const data = await request.json()
const emailStatus = await validateEmail(data.email);
if (emailStatus !== 'valid') {
return new Response(null, {
status: 500,
statusText: 'Email invalid',
headers: corsHeaders,
});
}
const subscribeStatus = await postToSendy(data);
return new Response(subscribeStatus, {
status: 200,
headers: {
'Content-Type': 'application/json',
...corsHeaders,
},
});
}
This function will accept JSON data. If it’s not JSON, the request will be denied. You may notice there are 2 new functions in this code, validateEmail() and postToSendy(), which we’ll also need to write.
First, let’s validate the email. This is super easy because the Zerobounce API is super simple to use (documentation can be found here, if needed):
JavaScript:
async function validateEmail(email) {
const ZEROBOUNCE_API_KEY = 'YOUR_API_KEY';
const zbRequest = await fetch(`https://api.zerobounce.net/v2/validate?api_key=${ZEROBOUNCE_API_KEY}&email=${email}`);
const response = await zbRequest.json();
return response.status;
}
You’ll need to replace YOUR_API_KEY with your Zerobounce API key we generated earlier.
This function sends the user’s email address to Zerobounce for verification. They will respond with the status. There are actually 7 status’ they can reply with, but to keep this tutorial as simple as possible we’ll only care about a “valid” response. Valid means that Zerobounce considers the user’s email is valid.
Finally, we need to write the function to send the data to the Sendy API. This code can be easily adapted to use any ESP API, such as Aweber.
JavaScript:
// POST data to the Sendy API
async function postToSendy(formData) {
const SENDY_API_KEY = 'YOUR_SENDY_API_KEY';
const SENDY_URL = 'YOUR_SENDY_URL';
formData.api_key = 'SENDY_API_KEY';
formData.boolean = true;
var queryString = Object.keys(formData)
.map((key) => key + '=' + formData[key])
.join('&');
const options = {
body: queryString,
method: 'POST',
headers: {
'content-type': 'application/x-www-form-urlencoded',
},
};
const sendyRequest = await fetch(SENDY_URL, options)
const response = await sendyRequest.text();
return response;
}
You’ll want to replace YOUR_SENDY_URL with your actual Sendy URL and YOUR_SENDY_API_KEY with your API key. As with the Zerobounce API key, it’s a wise thing to do to keep the key server-side like we’re doing to protect it.
If you need to reference the Sendy API documentation then you can find it here.
And that’s it for our Cloudflare Worker code. You can concatenate it all and click Save and Deploy in the Cloudflare Worker editor. The URL in the editor is where you’ll want to send the data from your form on your landing page.
Prepare Your Landing Page
As mentioned above, last week I did a post on submitting a HTML form with Javascript. We’re going to use that same code, but with a slight modification.In your script.js file on your landing page find the following code:
Where the arrow points, you'll want to insert this line of code:
data.list = params.list;
When you add your landing page to your tracker you'll want to append the Sendy list ID as a URL parameter:
And then the user will be subscribed to that Sendy list when they submit the form.
Next, starting at the script.js comment “// If the data on the form is valid, perform a POST request to my fake API" we need to modify the following:
- Change the URL to your Cloudflare Worker URL
- Change json() to text()
- Delete .status === 200 and replace it with === '1'
- Delete .error
Now you can be sure only valid emails are making it onto your email list and being posted back to your traffic source.
Last edited: