kreativsoehne/sulu-email-obfuscator-bundle
A Sulu CMS bundle for obfuscating email addresses in templates and content, helping protect them from spam bots while keeping mailto links usable for visitors. Lightweight integration for Sulu/Twig projects.
What this package is: a Sulu CMS bundle (Symfony, Twig) that post-processes the finished HTML response and reverses email addresses inside mailto: links, so scrapers harvesting the raw markup get garbage while the browser reverses it back. Note for Laravel readers: the concepts map cleanly (response middleware instead of a kernel.response listener, Blade directives/helpers instead of Twig filters), but the package itself is Sulu/Symfony — don't expect a service provider.
Minimal steps:
composer require the bundle, register it in config/bundles.php, and clear the cache.mailto: link on the site renders reversed.mailto: link and view the raw source. You should see the address reversed and a new data-obfuscated-email attribute on the anchor.Where to look first:
sulu_obfuscate_email and sulu_obfuscate_emails.Configuration class for the toggle(s) and any skip-list.data-obfuscated-email.First use case: an existing corporate site with a "Kontakt" page and footer mailto: links. You change zero templates, enable the bundle, and the global response pass handles both. That's the pitch: retrofitted obfuscation without touching a single .html.twig.
Global pass (default, zero-touch). Let the listener rewrite the final response. Use this for all normal page rendering. It's the lowest-effort path and keeps templates clean.
Opt-in per template via Twig filters. Use sulu_obfuscate_email when the template itself owns the address — e.g. you're building an href conditionally, embedding the address in a title or aria-label, or emitting it into a JSON-LD block that the response pass (correctly) won't touch. Use sulu_obfuscate_emails when you're rendering a list/string containing several addresses (team pages, multi-recipient contact blocks) rather than looping yourself.
Treat data-obfuscated-email as the public contract. It's both the browser's instruction and the listener's "already processed" marker. That makes it a legitimate hook for you: assert on it in functional tests, style it, or write your own small script that reads it and restores text for non-href uses. Don't strip it in a sanitiser.
Preview is a first-class concern, not an afterthought. Detection is via the preview request attribute, which is exactly what Sulu's admin preview sets. So editors see real addresses while the public site is obfuscated — verify this explicitly after install rather than assuming.
Caching / integration tips.
$response->getContent(), and a @obfuscateEmail Blade directive mirroring the Twig filters.Testing. Functional-test the raw response body (reversed string, attribute present) rather than the browser-rendered DOM. Snapshot/regression tests will churn the first time you enable this — regenerate them deliberately.
href values containing mailto: are reversed. Addresses in visible text, title=, alt=, value=, form action=, data-* attributes, JSON-LD, or inline JS strings all survive in plaintext. For those, use the Twig filters — that's precisely why they exist.script, style, textarea, title, and non-mailto link content. Don't "fix" this; reversing inside script/title breaks pages for no benefit.data-* attributes (or rewrites href), links break silently. Register after minification, or whitelist the attribute.mailto: links gives you two layers of mangling. Pick one. Similarly, mailto: query strings (?subject=, ?body=) plus percent-encoding can round-trip badly — test a link with a subject line.?preview=1, an IP allowlist, a staging env), it will not be recognised and your editor view will show reversed addresses. Set the preview request attribute yourself, or disable the bundle outside production.Configuration class instead of guessing option names; expect a global on/off at minimum.How can I help you explore Laravel packages today?