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

Email Sender Bundle Laravel Package

requestum/email-sender-bundle

Requestum EmailSenderBundle is a Symfony bundle that streamlines sending emails through configurable transports and reusable mailer services, with support for templated messages, attachments, and cleaner application code.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a Symfony bundle, not a Laravel package — the -bundle suffix, the DependencyInjection/ + Resources/config/ layout, and the requestum-team vendor all point to Symfony conventions. v1.0.1 ("Support Symfony 4") confirms the target platform, which is genuinely useful: you can now stop guessing whether registration happens in config/bundles.php or AppKernel::registerBundles(). It is the former. There is still no service provider, no facade, and no vendor:publish. Your realistic day-to-day options are (a) use it inside a Symfony service in a mixed stack, or (b) read its ~200 lines of source and port the logic. For a Laravel app, (b) is almost always cheaper.

Assuming a Symfony 4 host app:

  1. Check composer.json constraints before installing. Expect something like "symfony/symfony": "^3.4|^4.0" or a set of symfony/framework-bundle / symfony/twig-bundle constraints, plus "php": "^7.1". That second one is the practical blocker: on PHP 8.2+ you will need --ignore-platform-req=php or a fork. And nothing here supports Symfony 5, 6, or 7, which means adopting it also means adopting Symfony 4.4 — itself past end of security support.
  2. Install from VCS, not Packagist. With 1 star and 0 dependents, assume it is not reliably indexed. Add a repositories entry pointing at the GitHub URL and require the exact tag (1.0.1), not dev-master.
  3. Read three files first, in this order:
    • README.md — usually the only docs; expect it to be thin or stale relative to the code.
    • DependencyInjection/*Extension.php — gives you the config tree (transport, from-address, templates, retry, etc.) and the service alias you inject.
    • Resources/config/services.yaml (or .xml) — gives you exact service IDs and which interface is aliased for autowiring.
  4. Register the bundle in config/bundles.php: Requestum\EmailSenderBundle\EmailSenderBundle::class => ['all' => true].
  5. Configure minimally under config/packages/ using the alias from getAlias() (almost certainly email_sender). Start with just a transport DSN and a default from address.
  6. First use case — prove the wire, not the features. Inject the sender into a console command, render a trivial Twig template, send one email synchronously to a real inbox. Don't start with queueing, attachments, or bulk sends; confirm transport wiring and from-address first. Then immediately do the same send through a null transport in your test suite, because that's the only path you'll actually keep running.

If step 3 doesn't yield a coherent config tree, treat that as a signal to skip the bundle and write a 30-line wrapper over symfony/mailer yourself. You are not losing a feature set; you are losing an abstraction layer over a mailer you already have.

Implementation Patterns

Constructor-inject the interface, never the concrete class. The bundle's value is the alias it registers. Type-hint whatever interface the extension aliases (likely EmailSenderInterface or a mailer contract) so you can decorate or replace it later without touching call sites.

Wrap it in your own application-level mailer. This is the single most valuable pattern with a low-maturity, EOL-adjacent dependency:

App\Mail\MailerInterface  ->  RequestumSenderAdapter  ->  bundle service

All domain code depends on App\Mail\MailerInterface. Swapping to symfony/mailer later becomes a one-file change — which is exactly the migration you should plan for from day one, not a hypothetical.

Template rendering stays in your app. Don't let the bundle own your Twig templates. Render HTML/plain parts in your own service (or a Mailable-style value object), then hand the finished subject/body/recipients to the sender. Templates stay versioned next to the code that renders them, and your view layer doesn't couple to a package nobody is maintaining. If the bundle's config tree expects a template name rather than a rendered body, render into a string and adapt — don't put your templates in the bundle's resources directory.

Async by wrapping, not by hoping. The bundle almost certainly has no queue support. Put a Symfony Messenger message in front of it: dispatch SendEmailMessage, and have the handler call your MailerInterface. Retries, failure transport, and rate limiting come from Messenger (and the bundle's config tree may have its own retry block — do not configure both, or you'll get multiplied retry storms).

Testing: swap the transport, assert on the adapter. In config/packages/test/, point the transport at a null/in-memory DSN if supported. If it isn't, decorate the sender service with a spy that records calls. The adapter above is what makes this cheap, since you only spy on App\Mail\MailerInterface and never touch the bundle's internals in assertions.

Composition points worth using if present:

  • Symfony events around send (pre-send for audit, post-send for metrics) — check EventDispatcher usage in the source. With Symfony 4 + SwiftMailer, the relevant hooks may be Swift's Swift_Events_* rather than Symfony's mailer events; verify before wiring listeners.
  • Decoration (decorates: on the bundle's service ID) for "always BCC compliance address" or "block sends outside production."
  • A compiler pass if you need to tag and collect multiple senders/transports.

Gotchas and Tips

v1.0.1 caps the package at Symfony 4 — that's the headline, not a footnote. "Support Symfony 4" arriving as a patch bump tells you two things: the project was previously Symfony 3-era, and the maintainer treats compatibility with a major Symfony version as a bugfix. It also tells you there is no Symfony 5/6/7 support and, given the semver hygiene, no near-term plan for it. Symfony 4.4 LTS left security support in November 2023. You are adopting an unsupported framework line to use a package with one star and zero dependents.

Verify the mailer internals before you commit — expect SwiftMailer. Symfony 4 shipped with SwiftMailer as the default mailer; the symfony/mailer component only arrived in 4.3 and required explicit adoption, which a bundle targeting ^4.0 almost certainly didn't do. If you see Swift_Mailer, Swift_Message, or \Swift_* anywhere in the source, you're adopting a dead dependency chain (SwiftMailer EOL'd in late 2021). Grep the vendor directory first: grep -r "Swift_" vendor/requestum/. This single command should decide whether you proceed.

It will not work in Laravel. No ServiceProvider, no facades, no config/*.php merge, no vendor:publish. The bundle expects Symfony's DI container, its config component, and probably Twig's Environment. Laravel's Mail facade plus a Mailable already covers this ground with maintained code. Only consider it in Laravel if you're bridging to a Symfony service in a monorepo — and even then, an HTTP boundary or a shared library is cleaner.

The PHP constraint will bite before anything else does. A php: ^7.1 constraint blocks installation on PHP 8.2+ and produces a confusing solver error about symfony/polyfill-*. Don't reach for --ignore-platform-req=php reflexively: the reason the constraint is there is that the code likely uses patterns (implicit nullable params, dynamic properties on Swift classes) that are hard-deprecated or removed on PHP 8.x. Read the source before bypassing the check.

Alias mismatches break autowiring silently-ish. If you get Cannot autowire service ... no such service, run bin/console debug:container --show-private | grep -i email and confirm the alias registered by the extension. Bundles of this vintage frequently register services as private with no public alias, so $container->get() in a controller fails while constructor injection works — or vice versa. With Symfony 4 there's no --show-private on some versions; drop the flag if it errors.

Config tree quirks. Old extensions commonly use ->cannotBeEmpty(), ->isRequired(), or scalar-vs-array nodes that reject what the README shows. When configuration throws, run bin/console config:dump-reference <alias> (if the extension implements ConfigurationInterface properly) or bin/console debug:config <alias> to see what actually got merged. If config:dump-reference returns nothing, the extension has no proper Configuration class — another signal to walk away.

Debugging sends. Use bin/console debug:event-dispatcher to find mailer events, and the Profiler's Mailer panel in dev. The important diagnostic: if your send succeeds but nothing appears in the Mailer panel, the bundle is bypassing the framework mailer entirely and talking to SwiftMailer directly. That confirms the EOL finding above and means Symfony's own mailer config, DSNs, and test transports are all inert for this code path.

Staging safety. Before the first deploy, add a decorator or a kernel.environment guard that redirects or drops all outbound mail outside production. Old bundles rarely ship an honored "disable delivery" switch, and if the package bypasses the framework mailer, framework.mailer.dsn: 'null://null' may not stop it. Test this explicitly by deploying to staging and watching for real outbound mail.

Fork it deliberately. If you adopt it, immediately fork into your own V CS, pin 1.0.1, and add a replace entry in your root composer.json. With zero dependents there is no upstream pressure to fix anything, no Symfony 5+ path, and the repo could be archived without notice. Budget for owning these few hundred lines — and for finishing the migration to symfony/mailer within the same project, because the fork is a stopgap, not a destination.

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/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
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