Email harvesters and other bots roam the Internet looking for email addresses to add to lists that target recipients for spam. This trend results in an increasing amount of unwanted email. Learn how to create a simple mail address obfuscation using JavaScript.

Check this step-by-step guide.

Let´s Start.

Background

I like how Cloudflare obfuscate mails, googling around I found an Andrew Lock article explaining how to use a simple bitwise XOR using a key, and as I knew the technique, I decided to adapt it and do my own implementation.

If you want to skip the how-to and just use it you can visit the Encoder Page

XOR stands for exclusive OR. It is a logical operation that returns a positive or true result when either but not both of its two inputs are true. In other words, the output is true if the inputs are not alike otherwise the output is false.

The XOR algorithm is basically a simple substitution cipher. In other words, it just replaces each alphanumeric in a string that is fed into it with another number. Crucially, the algorithm is reversible. So if you feed the output string back into the same algorithm, you end up with the original string with the cipher removed. This kind of cipher is also called an additive cipher, and is the simplest kind of cipher there is.

Goal

Create a simple mail address obfuscation using just JavaScript for encoding and decoding our address. In order to encode we will need a string representing a valid email address and a numerical key from 0 to 255 (0 to FF in hex). Also we have to create a drop-in script that decode our emails, and a form to create the ciphered ones.

Encoder

The function will receive two parameters email and key and returns a string containing the concatenation of the key in hex and the result of applying XOR to every character of the mail address.

First, as key is a decimal number we have to convert it to hex and pad it with a zero in case is smaller than 1016

let encodedString = key.toString(16).padStart(2,'0')

Then we iterate trough the whole mail address doing a xor, padding and concatenating to encodedString

for ( let n=0; n < email.length ; n++ ) {
    encodedString += ( email.charCodeAt(n) ^ key ).toString(16).padStart(2,'0')
  }

The whole encoder code so far

function encodeEmail(email, key) {
  let encodedString = 
      key
      .toString(16)
      .padStart(2,'0')
  for ( let n=0        ; 
            n < email.length ; 
            n++ 
      ) {
          encodedString += 
          ( email
           .charCodeAt(n) ^ key 
          ).toString(16)
           .padStart(2,'0')
  }
  return encodedString
}

Decoder

As we can realize the new length will be originalLenght*2+2 as every char and the key will be represented by their hex value, so we have to pick the first two characters of the encoded string and covert it to decimal. Then we will repeat the operation using that value as key and doing xor and concatenating the rest.

const decodeEmail = (encoded) => {
  let
  decEml   = '' ,
  keyInHex = encoded.substr (0, 2) ,
  key      = parseInt (keyInHex, 16)
  for (let n = 2;
           n < encoded.length;
           n += 2
  ) {
      let
      charInHex = encoded.substr (n, 2) ,
      char      = parseInt (charInHex, 16) ,
      output    = char ^ key
      decEml += String.fromCharCode (output)
    }
    return decEml
}

Parser

In order to store our encoded address we will use the data attribute and we also will make a function to parse all of our encoded emails that have a certain class for instance eml .

Example Link:

<a href="#" class="eml" data-encoded= "9c...">[contact]</a>

Parse Function:

function parseEmail() {
  const
  eml =
  document.getElementsByClassName("eml")
  for (let i = 0; i < eml.length; i++) {
    let
    elEml = eml[i] ,
    encoded = elEml.dataset.encoded,
    decoded = decodeEmail(encoded)
    elEml.textContent = decoded
    elEml.href = 'mailto:' + decoded
  }
} parseEmail()

The Form Encoder

What we need

We will create a very basic form in order to encode and create the links also it will have the instructions that allow users to add the script needed to decode mails.

The form need some validations as we need an email address and a key from 0 to 255. You can check the full source code below.

In order to verify the address we use this function that returns true or false when an address is passed to it.

function validEmail(email) {
    const 
    res = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
    return res.test(String(email).toLowerCase())
}

In terms of design we will use https://simplecss.org a minimal CSS semantic framework.

Final Code

You can visit the page with the final result.

Or check this pen:

See the Pen Email Obfuscation by Luciano Fullstack (@lucianofullstack) on CodePen.