Guide Verify Emails BEFORE They're Added To Your List

Adsterra

Nick

🧙🏻‍♂️ Wizard 🔮
Staff Member
Community Leader
Joined
May 7, 2018
Messages
4,404
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:
BeMob + affLIFT
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.
 
Nice article. Did not know Cloudflare had this feature. =)
 
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%).
 
If you want to use this with aweber, you can switch out the sendy routine with a zapier webhook that integrates with aweber. And then you can turn off DOI. (because zerobounce does it for you). It makes is really easy for the end user, and increases CPA effectiveness.
 
My issue with ZeroBounce is they jacked up their prices by an INSANE amount not too long ago...Wasn't worth it at that point. I can't remember the exact amount but if I kept using them my expense with them would have gone from like $500/mo to $1,000-$3,000 per month easy.

I've started seeing them more and more, and their inbox presence has increased a lot over the years so the product was good and they built up a big clientele but they are not worth what they are charging. Even before the price increase I was already considering only using their service for some of my data. I much preferred EmailOversight.com (But then again, I had better pricing with EmailOversight due to knowing someone on the inside.)

If you only need to clean/verify at most 500 subscribers per month I suppose it's not too bad but there are far better options (Webbula.com comes to mind, they're pricey but definitely worth it. Their database and customer profiling is VAST)
 
Last edited:
Remember with email verification, not all companies are created equal, nor are they static! At times the IPs they use for cleaning for example, lets say Yahoo or Comcast will not be as good as other days.

Sometimes I would have to clean 5,000 yahoo emails with ZeroBounce and it would work. The next month I would clean another 5,000 Yahoo subscribers and I would get a TON of errors. So I had to use another company.

I've see this happen with other services and it's just the nature of how they clean. Sometimes even the verification companies IP's get blocked and causes issues with the end-user. Never be afraid to tell this to the service you are using and ask for replacement credits!

Best to always have a back up verification service to make sure emails were really verified!
 
Anyone ever use IPQS for this? I use it for the Peak Awards and it seems to work well!
 
Never used them before but just by looking at their site, I like that they go above and beyond just the usual verification tests and checks most services offer. That's a good sign.

What is their pricing like?
 
Last edited:
Never used them before but just by looking at their site, I like that they go above and beyond just the usual verification tests and checks most services offer. That's a good sign.

What is their pricing like?
I have a friends and family deal because I've known the owners for a long time but if you're interested I can try and get you a good one because the minimum "plan" they have right now is $2k/month. Obviously, they focused on enterprise. But, they have a free plan you can test.
 
I'll definitely keep that in mind. I got a big database that will need to be re-cleaned soon.
 
Top