2lenet/hermes-bundle
HermesBundle is a simple mail manager for the Crudit Bundle: create and send templated emails through Symfony Mailer. Per-template statistics track link clicks, and a statistics flag enables consent management links so recipients can manage consent. Install with composer require 2lenet/hermes-bundle...
Architecture fit. The package is a Symfony bundle, not a Laravel package — this remains the single most important fact. 2lenet/hermes-bundle is a mail management layer: Doctrine-backed Mail / Recipient entities, Twig + MJML templating, CKEditor-authored bodies, attachments, CC sublists, unsubscribe links, cancel-send, resend-per-recipient, status filtering, and a CruditBundle admin dashboard with translations. Delivery is delegated to Symfony Mailer. The durable product value is the template + recipient state model and admin workflow, not the send mechanism. For a Laravel codebase, only the data model and the cancel/resend semantics are portable; the DI wiring, entities, Twig rendering, and admin UI are all framework-specific glue you would rebuild.
The 1.14.5 patch sharpens this conclusion rather than softening it: the fix for mail status accounting for CC recipients landed in the Crudit integration (crudit#668), alongside a new Twig partial — not in the domain entity. Status derivation, in other words, is partly owned by the admin layer. That is presentation-adjacent logic you would have to reimplement anywhere Crudit is absent.
Integration feasibility. The transport layer is not the blocker — Laravel's mailer already sits on symfony/mailer, so MTP/API transports are shared. Real blockers, in order of severity:
Net: this is a port, not an integration. There is no adapter that makes it a Laravel package.
Technical risk.
| Risk | Severity | Note / Mitigation |
|---|---|---|
| Framework mismatch (Symfony → Laravel) | High | Only viable via fork-and-rewrite; not recommended |
| CruditBundle coupling | High | Now deeper: 1.14.5 puts status/CC logic in the Crudit integration, not just UI. A "trim the admin" fork is harder than previously assumed |
| Maintainer concentration | High | Small agency-backed project, ~2 stars, 0 dependents — effectively bus factor 1–2; plan to own a pinned fork |
| Doctrine schema ownership | Medium | Migrations land in your DB; audit PII fields on Recipient |
| Status semantics across To/CC | Medium | Historically computed from primary recipients only (corrected in 1.14.5); regression-test sent/failed reporting for CC-only and CC-failure cases |
| Queue/batch semantics unclear | Medium | Still unconfirmed whether sends are dispatched via Symfony Messenger; matters past a few thousand sends/month |
| Transport / deliverability | Low | Symfony Mailer is battle-tested; swap in SES/Postmark freely |
| Licensing / legal | Low | MIT, no vendor lock-in |
Key questions.
1.14.x pin if releases stop?Stack fit.
Migration path — Symfony + Crudit (recommended, if applicable).
composer require 2lenet/hermes-bundle, run the Flex recipe, register the bundle.Mail / Recipient schema for PII and indexing.null://).Indicative effort: 1–2 weeks to a first production send for one engineer familiar with Symfony.
Migration path — Laravel (recommended: do not port). Build a first-party equivalent on native primitives:
Mail/Mailable + Markdown or Blade views, a mail_templates table with versioning, a queued SendMailJob per recipient, Filament/Nova resource for admin CRUD, signed unsubscribe URLs, and the transport of your choice. Explicitly model status across To and CC independently — 1.14.5 is a useful pointer that single-recipient status flags are an easy thing to get wrong. This preserves the only concepts worth keeping — template-as-data and per-recipient status — without importing Doctrine, Twig, or Crudit.
Compatibility notes.
1.14.x). The release cadence is frequent and small (1.14.4 → 1.14.5 is a single PR), so unpinned upgrades invite churn from upstream releases that touch the admin templates.services.yaml; there is no config/mail.php analogue to publish.Sequencing (Symfony path). Spike in a branch → schema migration + PII review → template authoring → transport/queue configuration → unsubscribe/compliance sign-off → admin permissions and CC-status verification → staged cutover. Do the queue decision before template authoring; it changes how resend and cancel behave.
Maintenance. The project is actively released (1.14.5 latest, 1.11.0 translatable emails, 1.9.0 Symfony 8 support) with PHPStan and PHPUnit CI — better hygiene than most 2-star bundles. But it is agency-maintained with a very small contributor pool and 0 dependents, meaning you will be an early adopter and should budget for a pinned internal fork. 1.14.5 is a good-news signal — a one-line-ish correctness fix merged promptly — but it is also a reminder that you are tracking a fast, small-changelog release train. Treat "we can maintain this ourselves" as a prerequisite, not a fallback.
Support. No commercial support, no SLA, GitHub issues only. Expect to self-diagnose. The source is readable, which partially offsets thin documentation — the README defers to docs/index.md, and the 1.14.5 notes are a raw PR title, so release-note quality is low and you will need to read diffs for anything affecting status logic.
Scaling. Delivery scales fine — swap the Symfony Mailer transport for SES/Postmark/SendGrid. The scaling risk is on your database: one Recipient row per address, per-recipient error strings, resend actions, and CC sublists all imply write-heavy batch semantics. With CC recipients now folded into status, the per-mail status recomputation touch-points grow with CC list size — worth profiling on high-CC-volume mail. Above roughly 10k sends/month, verify batching and queuing before committing, and consider offloading recipient bookkeeping to a purpose-built ESP.
Failure modes to design around.
Ramp-up. For a Symfony/Crudit team: roughly 1–2 days for a mid-level engineer to be productive, mostly on template authoring conventions and Crudit admin wiring. For a Laravel team: weeks of adapter work plus a permanent maintenance obligation — the correct TPM call remains to decline adoption, harvest the data-model ideas (including explicit CC-aware status), and build the thin equivalent on native Laravel mail primitives.
How can I help you explore Laravel packages today?