Email Obfuscator

Anyone who publishes a mailto link on a contact page, a site footer, or a documentation site hands the same address to every crawler that visits. This encoder takes one address and returns markup that hides it from naive harvesters: numeric entities, a char-code list, Base64, or ROT13. Encoding runs in your browser, so nothing leaves the tab while you compare methods. Visitors still get a link that opens their mail client, while a regex over your raw HTML finds no @ sign to steal.

Obfuscate an address Runs in this tab. Nothing is uploaded.
Encoding method
Output updates as you type.
Live preview

How It Works

Hex and decimal entity methods walk the address character by character and print each code point as h or h, so the href attribute and the link text carry no @ and nothing a harvester pattern can match. Browsers decode numeric entities in attributes and in text, which is why the visible label and the target still resolve to the same address after parsing. The base64 method runs btoa over the string, parks the result in a data-b attribute, and lets a snippet call atob once the page loads. ROT13 shifts only letters, leaves @ and the dot untouched, and returns plain rotated text rather than HTML, which suits README files. Both entity forms stay valid HTML, so the browser follows a normal mailto link while a text scrape sees only a run of numbers.

The JavaScript method stores comma-separated char codes in a data-e attribute and leaves a placeholder in the span; a script maps each code through String.fromCharCode and assigns the joined text with textContent, so the address appears only after that assignment runs. Until then the displayed text and the stored value differ, which is what keeps a source scrape from seeing a readable address. The mailto builder is separate: it appends subject and body values with encodeURIComponent and joins the parameters with &. Keep an aria-label and readable visible text on the anchor, adding rel for links inside user-supplied content. Base64 has one limit worth knowing: btoa accepts Latin-1 characters only, so an address holding non-ASCII glyphs fails before any snippet exists.

Before and After

The same short address, hi@acme.io, as a crawler reads it and as this tool emits it. The first line is the markup a harvest regex matches; the span and script beneath it are what ships instead, and the second block shows the entity route for the same input.

Plain source, then the JavaScript output
<a href="mailto:hi@acme.io">hi@acme.io</a>

<span data-e="104,105,64,97,99,109,101,46,105,111">[email protected]</span>
<script>(function(){var d=document.querySelectorAll("[data-e]");for(var i=0;i<d.length;i++){d[i].textContent=d[i].getAttribute("data-e").split(",").map(function(c){return String.fromCharCode(+c);}).join("");}})();</script>
Hex entity output for the same address
<a href="mailto:&#x68;&#x69;&#x40;&#x61;&#x63;&#x6D;&#x65;&#x2E;&#x69;&#x6F;">&#x68;&#x69;&#x40;&#x61;&#x63;&#x6D;&#x65;&#x2E;&#x69;&#x6F;</a>

Use Cases

Developer Production Workflow
Linking a support address in a component library Footer, contact-page, and pricing links on a marketing site Documentation sites a crawler requests every night
An open-source README rendered on a docs host or wiki WordPress and blog posts edited by non-technical authors Handing the address to a contributor pasting it into a template
Prefilling a subject line for pricing-page enquiries Help centre and status pages maintained by support staff Rotating an address on a page that already draws junk

Common Mistakes and Troubleshooting

  • Shipping the markup without opening the live preview once. A stray space in the address or a quote mangled by a template engine shows up there first.
  • Pasting encoded output into a field that encodes a second time. The result becomes double-escaped text that no browser ever turns back into an address.
  • Expecting this to stop CAPTCHA-worthy spam. Harvesting is one path only, so pair the encoder with a contact form, rate limits, and server-side filtering.
  • Believing robots.txt or humans.txt protects the address. Those files ask polite crawlers to stay away, and harvesters simply ignore the request.
  • Letting a build pipeline rewrite the quotes or the script tag. Check the deployed HTML, since an aggressive minifier can mangle attribute quotes and break the snippet.
  • Dropping the aria-label or the visible text to shorten markup. Screen reader users then get a placeholder, and the link stops making sense out of context.

Best Practices

  • Pick the JavaScript char-code method for HTML pages you control, since it keeps the address out of both the attribute and the text.
  • Use hex or decimal entities wherever scripts may be blocked, including static hosts and pages read inside webmail.
  • Open the page with JavaScript disabled before release to confirm the fallback you expect is the one visitors get.
  • Offer a contact form beside every obfuscated link so visitors without a mail client still reach you.
  • Rotate the address on pages that attract junk, and forward the old one for a while rather than dropping it.
  • Pair the encoder with an inbound filter, because obfuscation stops collection while filtering stops delivery.

Frequently Asked Questions

Why does encoding stop naive email harvesters?

A basic harvester pulls your HTML and matches a pattern for mailto: or a bare local-part@domain, then stores every hit. Numeric entities, char-code lists, Base64, and ROT13 all fail those patterns, so the crawl returns nothing to send through. Browsers still resolve each form for a human visitor, so the link keeps working.

Does this stop a determined attacker or a CAPTCHA farm?

No, and no encoder should claim that. Someone who wants the address can read the decoded text once the snippet runs or lift a screenshot with OCR. What you change is cost: bulk crawlers get nothing while a targeted person must do real work. Add a contact form for everything else.

Which method should I pick for my site?

JavaScript char codes give the best mix of experience and search resistance: the plain address never sits in your HTML as text. Base64 behaves the same way but reverses instantly for anyone who recognizes it, so treat it as a convenience layer. Hex or decimal entities are the safer pick whenever scripts may be off, while ROT13 suits plain-text files rather than pages.

Will an encoded mailto link hurt my SEO?

Google does not generally penalize a page for an encoded mailto target, and visible anchor text still counts as a link. The tradeoff is that a crawler reading raw markup may miss the destination, so your address can vanish from extracted contact data. Keep visible text with the address on local-business pages, and fetch the page afterwards to see what Googlebot receives.

How does the JavaScript decode work?

The snippet stores the address as comma-separated character codes in a data-e attribute and leaves a placeholder in the span. On load, the script maps each code through String.fromCharCode and writes the joined result with textContent, so no part of it is parsed as HTML. Until that assignment runs the visible text and the stored value differ, which is the point. Keep an aria-label describing the link in plain words.

What else helps with spam besides encoding?

Obfuscation affects collection, not delivery, so add defenses on the receiving side. Keep the address out of static HTML by rendering it after load, plant an empty honeypot field in your contact form, and delay the submit button by a second. A server-side filter then catches whatever still arrives.

What happens when JavaScript is disabled?

The char-code and Base64 snippets leave their placeholder in place, so the span shows no address at all. Hex and decimal entities are the fallback: they are plain HTML that every browser decodes without a script and that survives environments which strip scripts. A contact form as the only public route is a third option. Check the page with scripting disabled before release.