Adding your email with Javascript

An often used method to put your email address on your site in a spam-proof manner is by using Javascript. Advantage of this method is that it is pretty much transparent to the end user, they can see and click on your email address just as always, while the spambot can’t make heads or toes of it. The downside is that it uses Javascript, so people must have a browser which supports it (all modern browsers do), and have it enabled.

Some of the script’s features:

To enable the script, you have to first fill in your email address in the script’s eml variable, then include the script in your document, add onload="putEmail(); to the document’s <body> tag, and finally put <span class="myemail">(need Javascript for email link)</span> (or something similar) everywhere you want to show your address. An example XHTML document is given below.

Update: nowadays I use a never method to insert emails through script. It uses a custom XML tag inserted in an XHTML page, providing neat markup and more flexible configuration of the email address to insert, but it only works on XHTML pages (and text/html in IE). You can see it at work on my about page.

The code

//
// Email address link javascript     (by Grauw)
// =============================
// Using standard DOM methods working in an XHTML environment.
//
// License: Public Domain (but feel free to mention my name ;))
//
// Usage:
// * Fill in your email address in the variable ‘eml’ below,
// * Put a tag with class="myemail" where you want the link,
// * Add onload="putEmail();" to your <body> tag.
//
function putEmail() {
    var eml  = 'email'              // The email address...
    eml += '@'
    eml += 'domain.com'

    var link = document.createElement("a");
    link.setAttribute("href", "mailto:" + eml);
    link.appendChild(document.createTextNode(eml));
    var spans = getElementsByClass("span", "myemail");
    for (var i = 0; i < spans.length; i++)
        spans[i].parentNode.replaceChild(link.cloneNode(true), spans[i]);
}

//
// Returns an array of elements with the given class
//
function getElementsByClass(elem, classname) {
    var classes = new Array();
    var alltags = document.getElementsByTagName(elem);
    for (i = 0; i < alltags.length; i++)
        if (alltags[i].className == classname)
            classes[classes.length] = alltags[i];
    return classes;
}

Example XHTML code using this script, with the important bits highligted:

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html
     PUBLIC "-//W3C//DTD XHTML 1.1//EN"
     "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
    <title>Email script test</title>
    <script type="text/javascript" src="email.js"></script>
</head>
<body onload="putEmail();">

<p>Email: <span class="myemail">(need JavaScript for email link)</span></p>

</body>
</html>

Some explanation of the code…

Let’s go in some more detail about what this script does. It’s fairly simple really, so I’ll keep it short.

function putEmail() {
    var eml  = 'email'              // The email address...
    eml += '@'
    eml += 'domain.com'

As the comment says, this is the email address you would want to insert. Putting it like this ensures that a spambot can not recognize it.

    var link = document.createElement("a");
    link.setAttribute("href", "mailto:" + eml);
    link.appendChild(document.createTextNode(eml));

This piece of code first creates an <a> tag, then adds a href attribute to it with the contents "mailto:" + the email address (so now there is a link the user can click on), and finally puts the email address as text inside it as well (to show to the user). This is the email link, however it has not been placed in the web page yet.

    var spans = getElementsByClass("span", "myemail");
    for (i = 0; i < spans.length; i++)
        spans[i].parentNode.replaceChild(link.cloneNode(true), spans[i]);
}

This part of the script first collects all <span> elements which have the ‘myemail’ class set, and then replaces each of them with a copy (‘clone’) of the link.

function getElementsByClass(elem, classname) {
    var classes = new Array();
    var alltags = document.getElementsByTagName(elem);
    for (i=0; i<alltags.length; i++)
        if (alltags[i].className == classname)
            classes[classes.length] = alltags[i];
    return classes;
}

The final part of the script is the getElementsByClass function used earlier in the script. Basically what this does is take all tags specified in the first parameter (in our case, ‘span’), and then look through all of them to see which have a matching classname. The ones which have are added to a result list, which is passed back to the calling function.

Note that instead of ‘span’ one could also choose another element, or you could even use ‘*’ (‘all elements’) meaning that it does not matter on which element you put the ‘myemail’ class. Small problem with ‘*’ is that it does not work in Internet Explorer 5, so if that is important to you, don’t use it. But unless you need it, you shouldn’t really use ‘*’ anyway, because it’s a bit slower.

Making it work in Internet Explorer 5

Note that I don’t see much point in this – few people are still using IE5 anyway and their numbers are decreasing rapidly (for indicative stats look at the W3Schools' browser statistics). But for the sake of it, here we go:

There is one issue with Internet Explorer 5 which prevents this from working, and that is that IE5 does not support the replaceChild method. There are two alternatives however: the first is to use appendChild instead, which IE5 supports. Downside of this is that it actually adds the link to the <span>’s contents instead of replacing it, so the ‘noscript’ functionality kind of gets lost. This is what you need to change:

   for (i = 0; i < spans.length; i++)
        spans[i].appendChild(link.cloneNode(true));

The second alternative can be found in a nonstandard extension Microsoft made called replaceNode. This one is supported on their older browsers, so the following addition should be enough to get everything working:

   for (i = 0; i < spans.length; i++)
        document.replaceNode ? spans[i].replaceNode(link.cloneNode(true)) :
        spans[i].parentNode.replaceChild(link.cloneNode(true), spans[i]);

It checks if replaceNode is supported, and if so uses that instead. And yes, I realize replaceNode actually looks a lot nicer than the stuff we have to do for replaceChild, but a standard isn’t a standard for nothing, and replaceNode isn’t in it (and hence not supported on most if not all non-IE browsers). :)

Well, that’s about all there is to say about this.

Grauw