moukail/verification-mail-bundle
A Symfony bundle for adding email verification to user registration, sending confirmation emails and handling verification links. It aims to simplify wiring verification into existing apps, but with no stars and minimal documentation, evaluate its maintenance and fit carefully before relying on it i...
Read the package name before the README: moukail/verification-mail-bundle is a Symfony bundle, not a Laravel package. The -bundle suffix, the Bundle class you'll find in src/, and the DependencyInjection/ + Resources/config/services.yaml layout are all Symfony conventions. There is no ServiceProvider, no extra.laravel block, and nothing Laravel's package discovery will pick up.
Where to look first, in order:
composer.json — check require for symfony/framework-bundle, symfony/mailer, and the PHP constraint. A 2021-12 release will likely say ^5.3|^5.4 or similar, which is the single biggest blocker for a modern Laravel app (Laravel 10/11 pull Symfony 6/7 components and Composer will refuse to resolve).src/*Bundle.php — the getContainerExtension() / bundle class confirms how the service is wired.src/DependencyInjection/Configuration.php — this is the authoritative source for the config root key, defaults, and required values. Do not trust README examples; they drift.src/EventSubscriber/ or src/EventListener/ — verification bundles almost always hook a registration/user.created event. That's where the actual workflow lives.README.md last — with 0 stars and 0 dependents, docs are the least reliable artifact in the repo.First use case: double opt-in email verification on registration — user registers, a tokenized link is mailed, the click flips a verified flag, and unverified users are blocked from certain routes. Laravel already ships this: MustVerifyEmail on the User model, the verified middleware, the verification.notice and verification.verify routes, and EmailVerificationRequest. Reach for this package only if you specifically need something Laravel's implementation doesn't do — a custom token table, a separate expiry policy, or admin-driven verification states.
Practical first step in a Laravel app:
composer require moukail/verification-mail-bundle --dry-run
The dry run tells you in ten seconds whether the Symfony version constraints can coexist with your laravel/framework lock. In most 2024+ apps the answer is no.
If you're actually in a Symfony app (the package's native habitat): register it in config/bundles.php, add the config block under whatever root key Configuration.php declares, wire your mailer transport, and attach your User entity to the bundle's verification contract (usually a trait or an interface with isVerified() / setVerified()). The subscriber does the rest on the registration event.
If you're in Laravel, port the pattern, not the package. Three viable shapes:
Native-first (recommended). Use MustVerifyEmail, the verified middleware, and signed URLs. Nine out of ten "I need a verification mail package" requests are already covered:
Route::get('/email/verify/{id}/{hash}', VerifyEmailController::class)
->middleware(['auth', 'signed', 'throttle:6,1'])
->name('verification.verify');
Token-table port. If the package's model is a DB-persisted token with a TTL (common in Symfony bundles that predate signed URLs), copy that shape: a verification_tokens migration with a hashed token column, an expiry timestamp, and a single-use flag. Replace the Symfony Mailer call with a queued Notification, and the event subscriber with an Eloquent created observer or a listener registered in EventServiceProvider.
Facade/adapter port. Wrap the verification logic behind your own interface (EmailVerifier::send() / ::consume()) and bind it in a service provider. This is worth the extra file: it lets you start with the package's semantics, swap to native later, and keeps Symfony types out of your controllers.
Other patterns that matter day-to-day:
throttle:6,1 on the resend route, plus a verification_sent_at column if you want friendlier UX messaging.auth:admin treatment; most bundle-era implementations assume a single firewall/provider.Mail::fake() in feature tests plus Notification::assertSentTo() covers the assertions.extra.laravel.providers, so composer require succeeds at best partially and then nothing happens. If Composer completes, you'll get the Symfony classes with no wiring. You'd be manually instantiating bundle services, which defeats the point.--dry-run first, and read the conflict output literally — it names the exact package and constraint that blocks you.symfony/mailer versions with known advisories.Configuration.php's ->rootNode() / ->children() — do not copy a README snippet.bin/console debug:event-dispatcher and the profiler's Mailer panel show whether the subscriber fired. In a Laravel port, MAIL_MAILER=log plus tail -f storage/logs/laravel.log, then Mail::fake() in a feature test to isolate delivery from logic.Resources/views. In Laravel the equivalents are a container binding to your own interface, and php artisan vendor:publish --tag=views if you port the templates.src/ for the state-machine ideas (token lifecycle, expiry, single-use) and reimplement in ~80 lines with MustVerifyEmail + a custom notification. You get maintained dependencies, no Symfony bridge, and a version of the flow you can actually debug at 2 a.m.How can I help you explore Laravel packages today?