Email Obfuscation: a Simple, Effective Implementation Email Obfuscation: a Simple, Effective Implementation

Email Obfuscation: a Simple, Effective Implementation

The article Email Obfuscation: What Works in 2024 by Spencer Mortensen1 explores various techniques to hide email addresses from spam bots while keeping them accessible to users. It evaluates methods such as plain text, HTML entities, CSS display properties, JavaScript techniques, and more, testing their effectiveness in blocking spam.

Some methods, such as CSS display: none and certain JavaScript techniques, are highly effective, while others, like HTML comments and symbol substitution, offer minimal protection.

CSS display: none

Most harvesters are unable to apply style rules, so this is one of the absolute best techniques. Be sure to add decoy tags so the harvester won’t be able to guess which parts to omit.

Include this HTML:

<span class="email">email@example<b>.example</b>.com</span>

And this CSS:

span.email b {
display: none;
}

This renders in the browser as:

This [technique] is fully accessible to everyone, including those who depend on a screen reader. But you must use display: none to hide the text: if you use any visual-only technique (such as shrinking the font size, or repositioning the text off screen), then you’ll break accessibility.

Hugo Shortcode

For Hugo websites, this technique can be implemented as a shortcode. Here’s how:

Step 1: Configure Default Email Address

Add a default email address to config/_default/params.toml as a fallback:

params.toml
# defaultEmail
defaultEmail = "email@example.com"

Step 2: Add CSS

Include the following CSS in assets/scss/common/_custom.scss:

_custom.scss
span.email b {
display: none;
}

Step 3: Create the Shortcode

Create a shortcode file at layouts/shortcodes/email.html:

email.html
{{- /* Set defaults and get args. */}}
{{- $address := index .Params 0 | default site.Params.defaultEmail }}
{{- /* Get parts. */}}
{{- $addressParts := split $address "@" }}
{{- $userName := (index $addressParts 0) }}
{{- $rootDomain := (index $addressParts 1) }}
{{- $rootDomainParts := split $rootDomain "." }}
{{- $domainName := (index $rootDomainParts 0) }}
{{- $topLevelDomain := (index $rootDomainParts 1) }}
{{- /* Render. */}}
<span class="email">
{{- printf "%s@%s<b>.%s</b>.%s" $userName $domainName $domainName $topLevelDomain | safeHTML -}}
</span>

This shortcode:

  • Retrieves the email address you provide, defaulting to the fallback email address if none is specified.
  • Splits the email address into its components: userName, domainName, and topLevelDomain.
  • Generates and renders the appropriate HTML structure for obfuscation.

Now, you can use the shortcode in Markdown with the default email address:

{{< email >}}

Or specify an email address:

{{< email "email@example.com" >}}

Astro Component

For Astro websites, this technique can be implemented as a component. Here’s how:

Step 1: Configure Default Email Address

Add a default email address to src/params.ts:

params.ts
export type siteParams = {
defaultEmail: string;
};
const siteParams: siteParams = {
defaultEmail: "email@example.com"
};
export default siteParams;

Step 2: Create the Component

Create a component file at src/components/Email.astro:

Email.astro
---
// Set defaults and get args
import siteParams from '../params';
const defaultEmail = siteParams.defaultEmail;
const { address = defaultEmail } = Astro.props;
// Get parts
const addressParts = address.split('@');
const userName = addressParts[0];
const rootDomain = addressParts[1];
const rootDomainParts = rootDomain.split('.');
const domainName = rootDomainParts[0];
const topLevelDomain = rootDomainParts[1];
---
<!-- Render -->
<span class="email">{userName}@{domainName}<b>.{domainName}</b>.{topLevelDomain}</span>
<style>
span.email b {
display: none;
}
</style>

This component:

  • Retrieves the email address you provide, defaulting to the fallback email address if none is specified.
  • Splits the email address into its components: userName, domainName, and topLevelDomain.
  • Generates and renders the appropriate HTML structure and CSS for obfuscation.

Now, you can use the component in MDX with the default email address:

import Email from '../../components/Email.astro';
<Email />

Or specify an email address:

import Email from '../../components/Email.astro';
<Email address="email@example.com" />

Conclusion

Spencer Mortensen’s analysis demonstrates that some email obfuscation methods, such as CSS display: none and certain JavaScript techniques, are highly effective, while others, like HTML comments and symbol substitution, offer little protection.

This guide explained how to use the CSS display: none technique to hide email addresses from spam bots and provided steps to implement it as a Hugo shortcode and an Astro component. I hope you find this information helpful in protecting your email addresses from spam!

Footnotes

  1. Email Obfuscation: What Works in 2025


← Back to blog