libre-informatique/email-bundle
A Symfony bundle from Libre Informatique that packages reusable email services, configuration, and integration points, helping PHP applications add email handling with less boilerplate and a consistent structure. It is intended for Symfony projects seeking a lightweight, maintainable email layer.
Before doing anything, read the package's composer.json and README.md. Two facts will immediately change your plan:
LibreInformatique\EmailBundle), designed to be registered in a Symfony kernel via config/bundles.php (Symfony 5+) or AppKernel::registerBundles() (Symfony ≤4). It has no service provider, no facade, no config publish command, and no Illuminate\Mail integration.LibrinfoCoreBundle. Zero stars, zero dependents, and an ambiguous NOASSERTION license mean there is no community path. If you are not already running the Libre Informatique stack, there is no standalone "getting started" — there is only inspection.Minimal steps to evaluate it against a Laravel codebase:
composer require libre-informatique/email-bundle --dry-run # check constraint conflicts first
Expect Symfony component conflicts against Laravel's pinned symfony/* versions. If the dry-run resolves, do not require into your app — clone the repo into a throwaway folder and read it.
Where to look first, in order:
composer.json — Symfony version constraints, PHP constraint, whether it depends on symfony/swiftmailer-bundle (dead since Symfony 4.3) or symfony/mailer.Resources/config/services.yml (or config/services.yaml) — the service IDs are the real API. The README will not tell you what actually exists.Entity/ or Model/ — if it ships Email/EmailTemplate entities, it carries Doctrine mapping assumptions that do not port to Eloquent.README.md and LICENSE — confirm the license grant before any commercial use.First use case (what you are actually extracting): ignore the transport. The reason to even open this repo is the pattern — composition service + persisted message + template rendering + deferred send. Replicate that in Laravel:
// Laravel-native equivalent of whatever the bundle's manager service does
Mail::to($recipient)->queue(new SystemNotificationMail($order, $locale));
If after reading the source you cannot articulate a behavior the bundle has that Illuminate\Mail + Mailables + a queued ShouldQueue + a MailLog model does not already give you, stop. That is the expected outcome.
Day-to-day, a Laravel developer's leverage here is reading the bundle for design intent and reimplementing it natively, not depending on it. The patterns worth lifting:
1. Compose/dispatch separation. Bundles of this vintage typically expose a manager that composes a message, persists it, then hands it to a transport. Mirror that in Laravel with a Mailable for composition and a queued job for dispatch. Keeping persistence out of the Mailable itself is the transferable lesson:
final class SendPersistedEmail implements ShouldQueue
{
public function __construct(public int $emailLogId) {}
public function handle(Mailer $mailer): void
{
$log = EmailLog::findOrFail($this->emailLogId);
if ($log->sent_at) return; // idempotency
$mailer->to($log->to)->send(new TemplatedMail($log));
$log->update(['sent_at' => now()]);
}
}
2. Store-then-send with status. The bundle's Email entity pattern (status, retry count, template reference, timestamps) is a reasonable audit-trail schema. Reuse the schema shape, not the class. Keep the send outside the DB transaction so a transport failure does not roll back business writes.
3. Template resolution at send time, not compose time. If the bundle stores a template name on the entity and renders at dispatch, copy that — it lets translations, tenant branding, and Twig/Blade changes apply to already-queued mail. In Laravel, store the template key + serializable context, render inside the Mailable's build().
4. Async wrapping. These bundles almost always send synchronously. Even if you were on Symfony, the correct move is a Messenger handler around the manager service. In Laravel this is already native (ShouldQueue, Mail::queue). No bridging work is required — Laravel's mail queue is the improvement.
5. If a bridge is genuinely forced (some unique attachment/workflow behavior you cannot reproduce): expose the existing Symfony email service as an internal HTTP endpoint, keep credentials and persistence on the Symfony side, and call it from Laravel behind your own MailerInterface. Do not share database tables or import bundle classes into Laravel. This adds operational surface area and should require a named justification.
6. Admin/UI. If the bundle ships Sonata or EasyAdmin classes for an email log, do not port them. Build a read-only Laravel list (Filament/Nova/custom controller) over your own email_logs table. Do not build a compose UI on top of the bundle.
NOASSERTION. This is a hard stop for commercial distribution until legal resolves it. Treat it as unresolved IP risk, not a permissive OSS dependency.symfony/* version pins, and even if it installs, the bundle expects a Symfony kernel, DI container, bundle config, and likely Doctrine entities. There is no facade and no Laravel service provider to lean on.LibrinfoCoreBundle is a silent failure. The bundle is a companion artifact. Expect compiler passes, base entity classes, and naming conventions from the core bundle. If that core bundle is not installed, services will fail to boot or autowire with confusing errors.swiftmailer-bundle (EOL since Symfony 4.3/6.0). If composer.json references Swiftmailer, the send path is dead and you are reading a historical artifact.Entity/ exists, the bundle assumes Doctrine ORM mappings and a migration. That schema does not transfer to Eloquent, so any "reuse" is re-implementation.php bin/console cache:clear behavior around bundle config differs from Laravel's config:cache; stale cached container config is a common false-negative when debugging.null:///array:// and assert on persisted entity state. In Laravel, use Mail::fake() and assert against your own EmailLog.Illuminate\Mail + Mailables + queued jobs + a mail_logs table behind an internal MailerInterface, and if you inherit a Librinfo deployment, contain it behind that interface so exiting is a contained change rather than a refactor.How can I help you explore Laravel packages today?