Email Spambot Buster

A simple and clean solution to spambots using a combination of unobtrusive DOM scripting and email munging; and no server-side requirements.

by Dennis Lembree
November 6, 2007

Spambots suck

I think we're all familiar with the problem here. Spambots, programs designed to collect email addresses from the Internet, attack our precious web sites. The result, of course, is spam. And lots of it. I think we get so used to spam in our email, that sometimes we forget how much we hate it! The MAAWG estimates that 80-85% of incoming mail is "abusive email", as of the last quarter of 2005. I would like to see more governments creating and enforcing laws against spam and spambots, although there have been agruments against spam laws. In the meantime, we developers must continue building in code to bust, or stop, the spambots behavior.

Busted solutions

Over the years there have been many solutions for busting a spambot, some good, some not-so-good. Let's take a took at a few of the most popular methods for blocking spambots. Our goal is a method that creates an email text link which supports accessibility, doesn't clutter up your nice markup, and degrades well.

Email address as an image

One method is to post all or part of an email address as an image. This is effective since spambots cannot read an image. But this solution is not accessible since screen readers cannot read an image either. And in order to make it accessible, you have to provide alternative text which would be the email address, which is what we're trying to avoid.

Build link with inline JavaScript

Another technique is building the link with inline JavaScript. Spambots, like search engine spiders, cannot decipher client-side code; it only reads the markup. So this method is effective, but is not a modern approach. It creates 1) ugly inline scripting code with the out-dated document.write method, and 2) requires a noscript tag (with munging, see below) to make the content accessible. Both practices are undesirable when using proper web standards and progressive enhancement techniques.

<script type="text/javascript"> 
var theuser = "nobody"; 
var thehost = "example.com"; 
var themessage = "Email Nobody"; 
document.write("<a href="+"mailto:"+theuser+"@"+thehost+">"+themessage+"</a>") ;
</script>
<noscript>
nobody@exampleREMOVEME.com
</noscript>

Note: ALA published a related article back in 2002, Win the SPAM Arms Race which offers a similar approach, but goes a step further by encrypting the JavaScript. But this solution also creates cluttered inline JavaScript and requires a noscript tag.

Using server-side scripting to run a contact form

Another method to stop spambots is to use server-side scripting to run a contact form. This way, an email address is completely eliminated from the client-side code. This protects the email address, but the goal of providing your email address for the user to send an email is not being met.

Email munging

The email address munging technique disguises an email address in a way that prevents computer software from reading the real address but still allows a human reader to reconstruct the original. This has recently become widely used on the web. An example is "john [at] gmail [dot] com"; simply replace "[at]" with "@" and "[dot]" with ".". This is something a human can easily interpret, but not an evil spambot. This method works well, but doesn't give us the email link which is part of our goal.

We will use this munging technique for the baseline of our Spambot Buster, and then use unobtrusive JavaScript to enhance it with an email link.

Examples of munging an email address

The Spambot Buster

The Spambot Buster is a technique that that creates an email text link which supports accessibility, uses unobtrusive scripting, and implements progressive enhancement. As noted above, images, inline scripts, and server-side forms are not feasible, so we'll start with plain "munged" email text and use unobtrusive JavaScript to enhance it with a "mailto:" link. And since spambots can't interpret the script, the email address is protected.

The X/HTML

The markup is exceptionally simple. Start by entering the email address using an email address munging technique. Then, wrap a SPAN around it with an ID attribute.

<span id="emailaddy1">Email Mr. Nobody at nobody -at- example dot NOSPAM com</span>

Ta da! That's it for the markup.

The JavaScript

Now we'll use unobtrusive JavaScript to replace the munged email address with a "normal" email link. If a user or robot doesn't have JavaScript available, the email will still be disguised by the munging. There are two parts to the JavaScript: setting the parameters for your email(s) in an array and the main function.

The array

To set the parameters for an email, simply enter five items separated by a comma in the value of the array:

  1. ID of the span
  2. text to be linked
  3. recipient in email address
  4. first part of the domain in email address
  5. second part of the domain in email address

Here is an example:

var emailAddress = new Array();
emailAddress[0] = "emailaddy1,Email Mr. Nobody,nobody,example,com";

This will eventually produce what a JavaScript-enabled browser will perceive as <a href="mailto:nobody@example.com">Email Mr. Nobody</a>

You can set as many emails as you'd like on a page. Just keep adding to the array:

emailAddress[0] = "emailaddy1,Email Mr. Nobody,nobody,example,com";
emailAddress[1] = "emailaddy2,Email Mr. John Doe,johndoe,example,com";
emailAddress[2] = "emailaddy3,Email Ms. Jane Doe,janedoe,example,com";
The function

After checking for DOM support, the spambotBuster function consists of only one for loop. The loop runs through the emailAddress array values and creates an email link for each value.

First, we ensure the browser can handle the DOM commands. If not, we end the function with a return.

if(!document.getElementById || !document.createElement) return;

Next, we create a for loop which holds the building blocks for the email addresses. The number of values in the emailAddress array determines how many times the loop will execute.

for (var i=0;i<emailAddress.length;i++) {
}

Then we split the value of the current array into another array, let's call it "x", so we have workable variables to piece together the email address link.

x = emailAddress[i].split(',');

Next, we assign the span element to a variable that we'll use when we build the email link node.

el = document.getElementById(x[0]);

Now we create the mailto link using the appropriate pieces.

theLink = "mailto:" + x[2] + "@" + x[3] + "." + x[4];

We're almost done! We now build the node that we'll use in the X/HTML document.

emailLink = document.createElement("a");
emailLink.appendChild(document.createTextNode(x[1]));
emailLink.href = theLink;

Finally, we replace the span in the HTML with the node.

el.parentNode.replaceChild(emailLink,el)

Here's the working function:

function spambotBuster() {
//ensure user agent can do DOM
if(!document.getElementById || !document.createElement) return;

//loop through email addresses
for (var i=0;i<emailAddress.length;i++) {
//put data in array
x = emailAddress[i].split(',');

//grab the email span element
el = document.getElementById(x[0]);

//create the actual link
theLink = "mailto:" + x[2] + "@" + x[3] + "." + x[4];

//build node for email link
emailLink = document.createElement("a");
emailLink.appendChild(document.createTextNode(x[1]));
emailLink.href = theLink;

//replace it!
el.parentNode.replaceChild(emailLink,el)
}
}

Call the function on page load, preferably with the addLoadEvent function by Simon Willison.

addLoadEvent(spambotBuster);

I suggest the addLoadEvent, but of course you can use the window.onload event or whatever's ideal for you for calling the function.

The Results

Now, when a JavaScript-enabled browser renders the code, "Email Mr. Nobody" diplays and is hyperlinked to "nobody@sample.com". If JavaScript is unavailable, the plain text "Email Mr. Nobody at nobody -at- example dot NOSPAM com" is displayed.

Bust enhancements

Now that we have the simple markup and the function, let's add in a couple enhancements to make the resulting code more usable and accessible. First, let's add a title attribute that will supplement the hypertext with a clear statement that this is an email link. It can be done with one simple line of code:

emailLink.title = "email link";

Next, let's add an email icon using CSS which will visually indicate that this is an email link. In the function, a rel attribute is added to the anchor tag. This can also be achieved with one line of code:

emailLink.rel = "email";

For the CSS, padding is added to the right of the link to make room for the image. Then the image is inserted as a background.

a[rel="email"] {
padding-right:18px;
background:url(icon_link_email.gif) no-repeat right center;
}	

Note: Not surprisingly, IE 6 cannot interpret the CSS2 selector for the rel attribute. Although less semantic, you can use a class attribute instead to achieve the same results.

That's it, buster

And now you have it. A technique that protects email links from spambots which supports accessibility, doesn't clutter up your nice markup, and degrades well.

Here is an example of the Spambot Buster code in action. You can download the Spambot Buster JavaScript here.