Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Sulu Email Obfuscator Bundle Laravel Package

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.

View on GitHub
Deep Wiki
Context7

Getting Started

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:

  1. composer require the bundle, register it in config/bundles.php, and clear the cache.
  2. Include the package's JS asset once in your base layout (it does the browser-side reversal). Without it every mailto: link on the site renders reversed.
  3. Load a page containing a mailto: link and view the raw source. You should see the address reversed and a new data-obfuscated-email attribute on the anchor.
  4. Ask an editor to open the same page in the Sulu preview — addresses must appear normal there.

Where to look first:

  • The response listener / event subscriber — this is the whole feature; check its event priority.
  • The Twig extension exposing sulu_obfuscate_email and sulu_obfuscate_emails.
  • The bundle Configuration class for the toggle(s) and any skip-list.
  • The JS asset — it's the contract partner for 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.

Implementation Patterns

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.

  • Make sure the listener also runs for responses served from your HTTP cache layer; if a cached page was stored already-obfuscated that's fine, but a cached un-obfuscated page silently defeats the whole thing.
  • On fragment/ESI-heavy pages, an address may span a fragment boundary and never be rewritten. Prefer the Twig filter inside such fragments.
  • If you're on Laravel: implement the same thing as terminable middleware that rewrites $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.

Gotchas and Tips

  • Scope is narrower than you think. Only 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.
  • Deliberately skipped: comments, script, style, textarea, title, and non-mailto link content. Don't "fix" this; reversing inside script/title breaks pages for no benefit.
  • This is obfuscation, not protection. Reversal is trivially undone by a human and by any scraper that bothers to check the attribute. Don't cite it as a GDPR measure or a substitute for a contact form.
  • Double-processing is the most likely self-inflicted bug. The marker prevents re-reversal, but nested handling, sub-requests, ESI, or a console command that calls the kernel can still run the pass twice. If links come out forward-facing (i.e. reversed twice = original), that's your culprit.
  • Listener ordering matters. Position relative to your HTML minifier and any tag-replacer matters: if the minifier runs after and drops unknown data-* attributes (or rewrites href), links break silently. Register after minification, or whitelist the attribute.
  • Beware stacked obfuscation. Cloudflare Email Obfuscation, Rocket Loader, or a marketing tag manager touching 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 detection is attribute-based only. If you add another preview mechanism (?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.
  • Accessibility / no-JS. Until the script runs, assistive tech and users with JS blocked read reversed strings. Keep the script early and blocking, and provide a plain contact page as fallback.
  • Config surface is tiny at v1.0.0. Read the bundle's Configuration class instead of guessing option names; expect a global on/off at minimum.
  • Extension points: the Twig extension (add your own filter variants) and the response listener (decorate it, or wrap it to add element/attribute exclusions). Both are stable seams; the internals are not — v1.0.0 is the first release ("Erste Fassung"), so pin the version and expect API churn in minor releases.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route