Guide Verify Emails BEFORE They're Added To Your List

EVERAD

Nick

šŸ§™šŸ»ā€ā™‚ļø Wizard šŸ”®
Staff Member
Community Leader
Joined
May 7, 2018
Messages
4,212
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!

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:
  1. In the left-hand menu, click API - Keys & Info
  2. 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:
  1. On the left-hand menu, click Workers.
  2. 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:
  1. Type a service name
  2. Select HTTP handler
  3. Click Create service

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:

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:
  1. Change the URL to your Cloudflare Worker URL
  2. Change json() to text()
  3. Delete .status === 200 and replace it with === '1'
  4. Delete .error

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. šŸ˜Ž
 
Last edited:
EVERAD
Hey Nick,

Looks fascinating but really very complicated at the same time.
So before I re-read every sentence 5 times and try to copy each step and double-check 10 times, can you please tell if this will work with Aweber.
This is what their script looks like. Do you think it will work with Aweber if yes can you please let the changes in this script.
<form action="https://www.aweber.com/scripts/addlead.pl" method="POST" accept-charset="utf-8">
<br>
<input type="email" name="email" id="email" class="aweber-input" required=""><br>
<div style="display:none;">
<label for="hp">HP</label><br>
<input type="text" name="hp" id="hp">
</div>
<input type="hidden" name="listname" value="awlist6164XXX">
<input class="submit-offer-link-unique" type="hidden" name="redirect" value="https://trk.THANKYOUPAGE.com/f77eae09-0235-4ba6-bd35-99453e4ae14">
<input class="submit-aweber" type="submit" name="submit" id="submit" value=">> CLAIM NOW <<">
</form>

Also, I know Sendy does not do any kind of verification but since I couldn't get Aws SES.
I had to use Aweber, and I think Aweber does some kind of verification. But I am not sure to what extent.
I think they just look for @ or something. And I am also not sure to what extent Zerobounce does their check but since they are an email cleaning service I think they would do a Ping test also to know if the email is active or not.
 
As a web dev, I have to say this guide is excellent, but if I were an affiliate who most probably doesn't know code, I'd probably be overwhelmed by all of this code. For any newbie, who's reading this post, I highly encourage you to learn JavaScript, it really helped me a lot as an affiliate.

Not only for cleaning the prelands I rip on spytools, but also to apply stuff like this haha.

Great content Nick! :cool:
 
For any newbie, who's reading this post, I highly encourage you to learn JavaScript, it really helped me a lot as an affiliate.
I quickly realized this after joining the forum šŸ˜…šŸ˜… I love coding and JavaScript so I just need to learn it now🤣
 
Hey Nick,

Looks fascinating but really very complicated at the same time.
So before I re-read every sentence 5 times and try to copy each step and double-check 10 times, can you please tell if this will work with Aweber.
This is what their script looks like. Do you think it will work with Aweber if yes can you please let the changes in this script.


Also, I know Sendy does not do any kind of verification but since I couldn't get Aws SES.
I had to use Aweber, and I think Aweber does some kind of verification. But I am not sure to what extent.
I think they just look for @ or something. And I am also not sure to what extent Zerobounce does their check but since they are an email cleaning service I think they would do a Ping test also to know if the email is active or not.
Verifying the email before submission works with Aweber, but you don't submit the email in the Cloudflare worker. You have to do it from your landing page still because of how Aweber's security is set up.

Plus, the code for your landing page is slightly different because you have to essentially override the default way the Aweber form works so it doesn't redirect to their error pages when there is an error.

There's too many changes to provide the code here. Contact me if you need help.
 
If you have an AWS account, then there's no way you couldn't manage to get SES.
Well, I am not sure if that makes me Ultra Stupid, but yeah they denied letting me out of the sandbox mode in SES.
I tried it with a different AWS account as well and gave them a different reason but they denied it again.
 
As a web dev, I have to say this guide is excellent, but if I were an affiliate who most probably doesn't know code, I'd probably be overwhelmed by all of this code. For any newbie, who's reading this post, I highly encourage you to learn JavaScript, it really helped me a lot as an affiliate.

Not only for cleaning the prelands I rip on spytools, but also to apply stuff like this haha.

Great content Nick! :cool:
Where is the best place to start?
 
Hi Nick, great guide! I was just wondering what would be the issue if I collected the email and uploaded it to zerobounce later, instead of at the point of submission.
 
Hi Nick, great guide! I was just wondering what would be the issue if I collected the email and uploaded it to zerobounce later, instead of at the point of submission.
Most people send conversions to their traffic source at the time of submission and if you’re using a CPA bidding model you’ll be telling their algorithm you’re getting conversions that are useless to you (approximately 15%).
 
Top