Best way to obfuscate an e-mail address on a website?

Viewed 105454

I've spent the past few days working on updating my personal website. The URL of my personal website is (my first name).(my last name).com, as my last name is rather unusual, and I was lucky enough to pick up the domain name. My e-mail address is (my first name)@(my last name).com. So really, when it comes down to guessing it, it's not very hard.

Anyways, I want to integrate a mailto: link into my website, so people can contact me. And, despite my e-mail address not being very hard to guess, I'd rather not have it harvested by spam bots that just crawl websites for e-mail address patterns and add them to their database.

What is the best way for me to obfuscate my e-mail address, preferably in link form? The methods I know of are:

<a href="mailto:x@y.com">e-mail me</a>

It works, but it also means that as soon as my website hits Google, I'll be wading through spam as spam bots easily pick out my e-mail address.

<img src="images/e-mail.png" />

This is less desirable, because not only will visitors be unable to click on it to send me an e-mail, but smarter spam bots will probably be able to detect the characters that the image contains.

I know that there is probably no perfect solution, but I was just wondering what everyone thought was best. I'm definitely willing to use JavaScript if necessary, as my website already makes use of tons of it.

29 Answers

I encode the characters as HTML entities (something like this). It doesn't require JS to be enabled and seems to have stopped most of the spam. I suppose a smart bot might still harvest it, but I haven't had any problems.

Personally, I've given up on hiding my email address. I find it easier to look into better spam-filtering solutions than worry about obfuscating. You could spend days trying to find the best way to obfuscate your address, and then all it takes is one person to sell your address to a spammer and all that work was useless.

The current accepted solution is to create a contact form that allows users to email you. If you receive a lot of spam from that (I don't on my site), then you can add a captcha for good measure, and you'll be far from the "low hanging fruit" at that point.

The fact of the matter is that if you are providing a link that a user can click on to pop open their email client with your address in the To: field, then the computer is able to decipher the email address from the page and so can a spam bot.

You mentioned this is for your personal website. On my personal site (for example, bobsomers.com) I just have a paragraph that says this:

The best way to get in contact with me before the new site is up is to send me an email. My email address is my first name at this website. If you can't figure it out from that hint, well, you might find email more of a challenge than figuring out my address.

People seem to be able to figure that out just fine, as I get legitimate email all the time. Sometimes the best solutions don't require writing any code. :)

Apparently using CSS to change the direction of your text works pretty well. That link has a test of a bunch of other obfuscation methods as well.

Whatever you use is inevitably going to be defeated. Your primary aim should be to avoid annoying the heck out of your users.

Don't use any obfuscation techniques here because it's probably the first place the email harvesters will look to find out how people are obfuscating emails. If you have to have your email address visible on the site don't just copy verbatim someone else's method; obfuscate it in some unique way that no other site has used so that your method won't be known to harvesters before they visit your site.

You could do as Google do on Google Code (and Groups). Display a par tof the email, and a clickable portion ("..."). Clicking that indicates you want to know the email, and you are asked to fill in a captcha. Afterwards the email (and others?) are visible to you.

One website I maintain uses a somewhat simplistic JavaScript means of (hopefully) keeping spambots out.

Email links call a JS function:

function sendEmail(name, domain) {
    location.href = 'mailto:' + name + '@' + domain;
}

To make sure only users who have JS enabled can see the link, write them out with this:

function writeEmailLink(realName, name, domain) {
    document.write('<a href="javascript:sendEmail(\''
      + name + '\', \'' + domain + '\')">');
    document.write(realName);
    document.write('</a>');
}   

The use of one JS function to write out a link that calls another means that there are two layers of protection.

I don't how well this would work. Could you not leave your email address out and make it load using an AJAX call once the page has finished loading. Not sure if spam bots can pick up the altered HTML or if they are clever enough to listen on other HTTP traffic to try and pick email addresses or if they just scan the page as it is received the first time.

If you work with PHP, you can grab a free script that does that automatically. It's called "Private Daddy" and we use it for our own online audio streaming service. Just one line of code and it works out of the box... you can grab it here

Honestly, your problem may be moot if you asked the question of whether or not a mailto is really what you want to use. A lot of people who use web mail, for example, or do not have the proper mail client setup in their browser are not going to benefit from a mailto. You are exposing your email address for a function that isn't going to work for a large portion of your users.

What you could do instead is use a form to send the e-mail behind the scenes so that the e-mail address is hidden and you don't have to worry about the poor saps who won't benefit from a mailto.

If you say on your site that "My e-mail address is (my first name)@(my last name).com.", and your first name and last name are pretty darn obvious, that seems to be the best spam protection you're going to get.

Since this solution is not mentioned anywhere, but works well for me:

I do this:

  • create a mailto link with fake email. I like admin@localhost.localdomain for obvious reasons: Spammer might spam his own botnet when using this address unchecked.

  • cypher real email address and put it in an unrelated but findable hidden span or whatever element you like. Obviously to obfuscate the email and hide it from the harvester. Depending on your project structure, you might even want to put it in a JS or Session variable.

  • create a click handler for these links after a second that decyphers and write the correct email address into the fake mailto link not preventing defaults. I do not think that crawlers click on mailto links, but if they would, they probaby won't wait a second, while a human being would have to be extremly fast to click a link in the first second after pageload.

Now you have a fully functional but obfuscated, honeypoted and timesecured mailto link.

Working example php file:

<html>
<head>
<title>E-Mail Obfuscating</title>
</head>
<body>
<?php
$email = "example@email.org";
echo "<a class='emailLink' href='mailto:admin@localhost.localdomain' >Send me an e-mail!</a>"
    ."<span style='display:none' data-hash='" . base64_encode($email) . "' />";
?>
<script>
<!--
var emailLinks = document.getElementsByClassName("emailLink");
setTimeout(function() {
    for(var i=0; i <emailLinks.length; ++i){
        emailLinks[i].addEventListener("click", function(){
            let encodedEmail = this.nextSibling.getAttribute('data-hash');
            let decodedEmail = atob(encodedEmail);
            this.href = "mailto:" + decodedEmail;
            this.text = decodedEmail;
        });
    }
}, 1000);

-->
</script>
</body>
</html>

May the code be with you.

What if creating a link "Contact me" pointing to a directory protected by a password? Of course, you have to give the pass to access.

"Contact me" > ••••••••••• > contact/index.html

Once accessed, the contact/index.html page reveals the email, a mailto for instance.

My solution is to rearrange the characters using css and replacing the element on hover. No change is visible to the user.

const obscureHoverReverseMailTo = input => `<span style="display: inline-flex; color: rgb(0, 0, 238); cursor: pointer; text-decoration: underline;" onmouseover="const newContent = [...this.children].sort((a, b) => a.style.order - b.style.order).map(el => el.innerText).join('');this.outerHTML = \`<a href='mailto: \${newContent}'>\${newContent}</a>\`">${input.split("").map((char, index) => `<span style="order: ${index}">${char}</span>`).sort(() => 0.5 - Math.random()).join("")}</span>`;

const obscureHoverReverseMailTo = input => `<span style="display: inline-flex; color: rgb(0, 0, 238); cursor: pointer; text-decoration: underline;" onmouseover="const newContent = [...this.children].sort((a, b) => a.style.order - b.style.order).map(el => el.innerText).join('');this.outerHTML = \`<a href='mailto: \${newContent}'>\${newContent}</a>\`">${input.split("").map((char, index) => `<span style="order: ${index}">${char}</span>`).sort(() => 0.5 - Math.random()).join("")}</span>`;

document.getElementById("testRoot").innerHTML = obscureHoverReverseMailTo("hello@example.com")
<div id="testRoot"></div>

<input type="text" onkeyup="document.getElementById('testOut').innerHTML = obscureHoverReverseMailTo(this.value)">
<div id="testOut"></div>

here is the function if you have something else to hide:

const obscureHoverReverse = input => `<span style="display: inline-flex" onmouseover="this.outerHTML = [...this.children].sort((a, b) => a.style.order - b.style.order).map(el => el.innerText).join('')">${input.split("").map((char, index) => `<span style="order: ${index}">${char}</span>`).sort(() => 0.5 - Math.random()).join("")}</span>`;

I agree with @srobinson in that using an online form for encoding to html entities seems a little shady. A few lines of python will do it for you:

def htmlEntities( string ):
    return ''.join(['&#{0};'.format(ord(char)) for char in string])

htmlEntities("barnstable@example.com")

the above returns:

'&#98;&#97;&#114;&#110;&#115;&#116;&#97;&#98;&#108;&#101;&#64;&#101;&#120;&#97;&#109;&#112;&#108;&#101;&#46;&#99;&#111;&#109;'

Which is barnstable@example.com encoded to HTML Entities (surrounded by single quotes).

Simple JavaScript-unaware bots typically look for mailto: and/or @ in HTML page contents. Obfuscating these keywords will dramatically decrease chances of email address scraping.

A Base-64 encoded URL template mailto:%user%@%domain% can be employed:

function contact(user, domain = location.hostname) {
  const template = atob('bWFpbHRvOiV1c2VyJUAlZG9tYWluJQ==');
  location.href = template
    .replace('%user%', user)
    .replace('%domain%', domain);
  return false;
}

Where 'bWFpbHRvOiV1c2VyJUAlZG9tYWluJQ==' is btoa('mailto:%user%@%domain%').

HTML links would need to be updated as follows:

<a href="javascript: contact('x', 'y.com')">e-mail me</a>

Furthermore, javascript: addresses can be hidden from the users:

<a href="#" onclick="return contact('x', 'y.com')">e-mail me</a>

The return statements prevent the page navigation to the # anchor.

Related