

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:
# defaultEmaildefaultEmail = "email@example.com"
Step 2: Add CSS
Include the following CSS in assets/scss/common/_custom.scss
:
span.email b { display: none;}
Step 3: Create the Shortcode
Create a shortcode file at layouts/shortcodes/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
, andtopLevelDomain
. - 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
:
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
:
---// Set defaults and get argsimport siteParams from '../params';const defaultEmail = siteParams.defaultEmail;const { address = defaultEmail } = Astro.props;
// Get partsconst 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
, andtopLevelDomain
. - 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
← Back to blog