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

Filament Email Laravel Package

rickdbcn/filament-email

A Filament plugin for managing email in your admin panel: compose and send emails, build reusable templates, and keep track of outgoing mail—all from a clean, native Filament interface.

View on GitHub
Deep Wiki
Context7

Getting Started

rickdbcn/filament-email adds an Email section to a Filament panel: a database-backed email log (every message that passes through the plugin's mailer) and email templates you can reuse and resend from the admin UI. The v2.3.0 release is a compatibility-only bump (adds Laravel 13.x support via laravel-shift); there are no new features, config keys, or breaking changes relative to v2.2.0.

Minimal setup:

  1. composer require rickdbcn/filament-email — on Laravel 13 you must be on ^2.3.0; on Laravel 11/12 either ^2.2 or ^2.3 is fine.
  2. Publish and run the migrations:
    php artisan vendor:publish --tag="filament-email-migrations"
    php artisan migrate
    
  3. Publish the config if you intend to change the table names, storage disk, or mailer wiring:
    php artisan vendor:publish --tag="filament-email-config"
    
  4. Register the plugin on the panel you want the resources to appear in:
    public function panel(Panel $panel): Panel
    {
        return $panel
            ->plugin(\RickDBCN\FilamentEmail\FilamentEmailPlugin::make());
    }
    

Where to look first: the published config/filament-email.php. It controls the model bindings, the storage disk for attachments, and the mail-driver/mailer integration. Reading it before writing any code saves you from fighting defaults later.

First use case: route a single mailer through the plugin and confirm rows land in the log table. Point one mailer in config/mail.php at the plugin's transport, send a Mail::to(...)->send(...) from php artisan tinker, then open the Email resource in the panel. Once you can see that message, you have verified migrations, config, and transport in one shot — everything else is UI and templating on top.

Implementation Patterns

Two independent halves — adopt them separately. The log (capture) and the templates (compose/resend) are decoupled. Many teams only want the audit trail of outbound mail and never touch the template resource; others only want a UI for editing transactional copy. Decide which half you need before wiring the panel, because the template half is the one that pulls in editor assets and policy decisions.

Capture via the mailer, not via Mail::fake()-style interception. The reliable pattern is to give the plugin its own mailer entry in config/mail.php and use that mailer explicitly for the mail you want recorded:

Mail::mailer('filament-email')
    ->to($user->email)
    ->send(new InvoiceReady($invoice));

Keeping it as a named mailer rather than swapping the global default means password resets, verification mail, and third-party package mail don't pollute the log — and it makes it trivial to disable capture in a given environment by pointing that mailer back at SMTP.

Templates as the source of truth for editable copy. The pattern that pays off is: define the template row in a seeder (so it exists in every environment, including CI), then have application code resolve it by a stable key and send it with a variable payload. Application code holds the key and the variables; the admin holds the wording. Keep the variable list documented next to the seeder, because there is nothing stopping an editor from renaming {{ customer_name }} in the UI and silently breaking rendering.

Drive sends from Filament actions with a service behind them. Resist putting send logic directly in an Action::make()->action(...) closure. A small MailerService (or a static method on your own wrapper class) that takes a template key + recipient + variables gives you: testability without the panel, one place to add retry/queue logic, and a single seam to swap the plugin out if you ever need to. The Filament action then becomes two lines.

Policies and tenancy are your responsibility. The resources ship with broad defaults. In a multi-tenant panel you will want to scope the email log to the current tenant (otherwise the outbox is a cross-tenant data leak) and gate the template resource so only certain roles can edit copy. Do this with a global scope on the published model plus a policy — both are extension points rather than config flags.

Testing. For behaviour, Mail::fake() still works and is the right tool — assert the mailable, not the DB row. For the log itself, assert directly against the plugin's model after an integration send, and remember the row is written by the transport, so a faked send will not produce one. Test template rendering as a pure unit: given a template body and a variable array, assert the output.

Gotchas and Tips

  • Laravel 13 needs ^2.3.0. If you pin ^2.2 you will get an unsatisfiable constraint on Laravel 13. Nothing else changed in this release, so upgrading from 2.2 to 2.3 is a safe, zero-migration bump.
  • Published migrations are yours now. Upgrading the package does not re-publish or re-run schema changes. If a future release adds columns, you will need to publish again and diff by hand — keep an eye on the migrations directory in the repo rather than assuming composer update covered it.
  • php artisan config:cache and mailer changes. Deploy pipelines that cache config will happily serve a stale mail.php. If mail stops being logged after a deploy, clear config cache before debugging the transport.
  • Queued mail and the log's timing/contents. A queued mailable is captured when the worker sends it, not when you dispatch it — so the log entry appears later, and a failed job may leave no row at all (or an error-state row, depending on your config). Don't build "did we email this user?" checks against the log without accounting for queue latency and failures.
  • The table grows forever. There is no built-in retention. Schedule a pruning job (delete rows older than N days, keeping failures if you care about them) from day one; retrofitting pruning onto a 2 GB table is unpleasant. Same for attachment blobs if you store them rather than store paths.
  • Attachments and the storage disk. Paths in the log are resolved against the configured disk at resend time. Move a file, rotate a bucket, or change the disk config, and historical resends break even though the original send succeeded. Prefer immutable object keys over user-supplied filenames.
  • Template HTML is rendered, not sanitised on your behalf. If non-technical users can edit templates, you have handed them a way to inject markup into transactional mail. Restrict the template resource to trusted roles, and treat any variable interpolated into a template as needing escaping in the application layer.
  • Resends create new log rows pointing at the same content. That is correct behaviour, but it means "count of emails sent to this address" is not "count of distinct messages". Decide which one your reporting needs before you write the query.
  • Debugging a missing log row, in order: (1) is this mail actually going through the plugin's mailer? (2) is the queue worker running the new code and new config? (3) did the migration run in this environment? (4) is a global scope or policy hiding the row from your user rather than the row not existing? The fourth is the most common false alarm.
  • Extension points, in rough order of safety: config overrides → policies and global scopes on the published model → subclassing the resource and registering the subclass → forking. The first two will survive package upgrades; the last two will not.
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.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager