tkeer/mailbase
Mailbase is a Laravel package that captures outgoing emails and stores them in your database, with a built-in web interface to browse and preview messages. It helps debug mail delivery and keep an audit trail without relying on external email services.
composer require tkeer/mailbase
Tkeer\Mailbase\MailbaseServiceProvider in config/app.php.php artisan vendor:publish --provider="Tkeer\Mailbase\MailbaseServiceProvider" (or --tag=mailbase).mailbase_emails table exists: php artisan migrate (confirm the provider loads the package migration; some versions require publishing first).MAIL_DRIVER=mailbase in .env. On Laravel ≥7: define a mailer in config/mail.php with ['transport' => 'mailbase'] and set MAIL_MAILER=mailbase./mailbase in the browser (default prefix; overridable in config/mailbase.php).First use case: replace log/array mail during local development. Send mail as you normally would —
Mail::to($user->email)->send(new WelcomeMail($user));
— then open /mailbase and you'll see the rendered message in a list, without spamming a real inbox or paying for Mailtrap.
Scope the driver to local/testing only. Keep smtp (or a real ESP) in production. The cleanest pattern is to set MAIL_MAILER=mailbase in .env.local and let .env for prod carry smtp. Never bake mailbase into a shared .env.example.
Laravel 7+ mailer wiring. Newer Laravel versions use named mailers, not a single MAIL_DRIVER. Add:
'mailers' => [
'mailbase' => ['transport' => 'mailbase'],
// ...
],
and set MAIL_MAILER=mailbase. If the package only ships a Mail::extend('mailbase', ...)-style hook, you may need to call it from a service provider — check vendor/tkeer/mailbase/src before wiring.
Queued mail and notifications. Anything routed through the Mail facade is caught automatically, including Notifiable mail notifications and Mail::raw(). With QUEUE_CONNECTION=sync locally, the email appears immediately after the request; with database/redis, run php artisan queue:work and the stored row appears when the job runs. This makes mailbase a decent smoke-test for "did the mailable actually build?"
Testing stays on Mail::fake(). Do not assert against mailbase_emails in feature tests — use Mail::assertSent(WelcomeMail::class). Keep mailbase for eyeballing rendered HTML and headers; it is a viewer, not a test harness. If you do want to inspect stored rows in a test, query the table directly:
$this->assertDatabaseHas('mailbase_emails', ['subject' => 'Welcome']);
Custom route and middleware. In config/mailbase.php change the route.prefix and add middleware (e.g. ['web', 'auth']) so the viewer isn't wide-open on a team LAN or staging box. This is the main extension point most teams touch.
Cleanup in your reset flow. The table grows fast once seeders and test emails fire. Add DB::table('mailbase_emails')->truncate() to your migrate:fresh seed run, or schedule a small artisan command. Treat it like storage/logs/laravel.log — disposable.
InvalidArgumentException: Unsupported mail transport [mailbase]. Confirm registration in vendor/; if it silently no-ops, fork it or register the transport yourself in a small service provider.MAIL_DRIVER vs MAIL_MAILER. Laravel 7 renamed the env key. Copying an old README is the #1 reason "nothing shows up."config/mailbase.php or config/mail.php, run php artisan config:clear. If you're switching environments, config:cache in prod must be re-run or you'll ship a cache that still points at mailbase.php artisan migrate and verify mailbase_emails exists before flipping the env var.web middleware by default. A /{any} catch-all or an existing mailbase named route can shadow or be shadowed — check php artisan route:list | grep -i mailbase.storage/logs/laravel.log and failed_jobs.tenant_id column, search, or a Vue/Blade filter is often faster than working around the defaults — that's the intended extension point for a package this size.How can I help you explore Laravel packages today?