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 Mail Laravel Package

jeffersongoncalves/filament-mail

Complete email management UI for Filament, built on laravel-mail. Browse and resend mail logs with HTML preview and attachments, edit multi-locale database templates with version history and live preview, send test emails, and manage delivery analytics and suppressions.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation

    composer require jeffersongoncalves/filament-mail
    

    Publish the package assets and config:

    php artisan vendor:publish --provider="JeffersonGoncalves\FilamentMail\FilamentMailServiceProvider" --tag="filament-mail-config"
    php artisan vendor:publish --provider="JeffersonGoncalves\FilamentMail\FilamentMailServiceProvider" --tag="filament-mail-assets"
    
  2. Run Migrations

    php artisan migrate
    
  3. Register the Plugin Add to app/Providers/Filament/AdminPanelProvider.php:

    return [
        // ...
        'plugins' => [
            \JeffersonGoncalves\FilamentMail\FilamentMailPlugin::make(),
        ],
    ];
    
  4. First Use Case

    • Navigate to the Mail section in Filament.
    • Use the Templates tab to create a new email template (supports multi-locale editing).
    • Send a test email via the Logs tab to verify the workflow.
    • Once real traffic is flowing, open the Campaigns tab to compare delivery, open, click, bounce and complaint rates across campaigns side by side.

Upgrading from < 1.5.0: the new Campaigns page requires jeffersongoncalves/laravel-mail ^1.4 with campaigns enabled. Bump the dependency and confirm the feature flag before pulling this release:

composer require jeffersongoncalves/laravel-mail:^1.4

Implementation Patterns

Core Workflows

  1. Template Management

    • Create/Edit Templates: Use the WYSIWYG editor for HTML content with multi-locale support (e.g., en, pt).
      // Define a template in a migration or seeder
      \JeffersonGoncalves\LaravelMail\Models\Template::create([
          'name' => 'Welcome Email',
          'subject' => 'Welcome to Our Platform',
          'html' => '<h1>Hello, {name}!</h1>',
          'locales' => json_encode(['en' => ['subject' => 'Welcome...'], 'pt' => ['subject' => 'Bem-vindo...']]),
      ]);
      
    • Reusable Components: Store common snippets (headers, footers) as separate templates and embed them using {{ template('footer') }}.
  2. Email Sending

    • Via Code:
      use JeffersonGoncalves\LaravelMail\Facades\LaravelMail;
      
      LaravelMail::send([
          'template' => 'welcome_email',
          'to' => '[email protected]',
          'data' => ['name' => 'John Doe'],
      ]);
      
    • Via Filament UI: Use the Logs tab to manually send emails with pre-filled templates.
  3. Analytics & Tracking

    • Dashboard Insights: Monitor open rates, click rates, and bounces in the Analytics tab.
    • Event Hooks: Extend tracking by listening to mail.sent or mail.opened events:
      event(new \JeffersonGoncalves\LaravelMail\Events\MailSent($mail));
      
  4. Campaigns & Per-Campaign Reporting (new in 1.5.0)

    • What it gives you: A dedicated Campaigns page that groups activity by campaign (mail tag) and reports, per campaign:
      • delivery rate
      • open rate
      • click rate
      • click-to-open rate
      • bounce rate
      • complaint rate
      • plus a roll-up table of all campaigns side by side and a list of the most clicked links.
    • Tag your sends so they land in the right campaign. The campaign is derived from the Laravel Mail "mail tag", so set it at send time:
      LaravelMail::send([
          'template' => 'welcome_email',
          'to' => '[email protected]',
          'data' => ['name' => 'John Doe'],
          'tags' => ['spring_promo_2025'], // becomes the campaign grouping key
      ]);
      
    • Consistent naming pays off: the Campaigns page groups by tag verbatim, so adopt a convention (e.g. {product}_{goal}_{yyyy_mm}) — otherwise spring-promo and Spring_Promo show up as two separate campaigns.
    • Use it to compare, not just to report: the side-by-side table is the fastest way to answer "did this send beat the last one?" — keep a control campaign (e.g. newsletter_control) permanently in the list as a baseline.
    • Most clicked links is your content signal: it tells you which CTA survived the template render and where to focus A/B copy changes. If a link you know you sent never appears, the click wasn't tracked (see Gotchas).
  5. Suppression Lists

    • Manage Opt-Outs: Use the Suppression tab to add/remove emails from suppression lists.
    • Programmatic Control:
      $suppression = \JeffersonGoncalves\LaravelMail\Models\Suppression::create([
          'email' => '[email protected]',
      ]);
      

Integration Patterns for Campaigns

  • Campaign per logical blast: one tag per batch, not per recipient. The page aggregates by tag, so tagging per-user will produce thousands of one-row campaigns.
  • Feed it from existing jobs: if you already dispatch mail from a queue job, just add the tag — no other wiring is needed for the Campaigns page to pick the data up:
    Mail::to($user)->queue(
        (new CampaignMailable($user))->tag('onboarding_step_2')
    );
    
  • Correlate with your own reporting: the campaign tag is also available on the underlying mail record, so you can join it in your own queries/exports rather than re-parsing Filament screens.

Integration Tips

  • Queue Emails: Configure config/filament-mail.php to queue emails by default:
    'queue' => true,
    
  • Custom Mailables: Extend the package’s Mailable class to integrate with existing Laravel mailables:
    use JeffersonGoncalves\LaravelMail\Mailables\Mailable;
    
    class CustomMailable extends Mailable
    {
        public function build()
        {
            return $this->subject('Custom Subject')->view('emails.custom');
        }
    }
    
  • Localization: Override locale-specific templates via language files (resources/lang/{locale}/filament-mail.php):
    return [
        'templates' => [
            'welcome_email' => [
                'subject' => 'Personalizado para {locale}',
            ],
        ],
    ];
    

Gotchas and Tips

Pitfalls

  1. Campaigns Page Is Empty After Upgrading to 1.5.0

    • Two causes, in order of likelihood:
      1. jeffersongoncalves/laravel-mail is still < 1.4 — the page renders but there is no campaign data to read.
      2. Campaigns are not enabled in laravel-mail's config. The release notes are explicit: the feature "requires jeffersongoncalves/laravel-mail ^1.4 with campaigns enabled". Enable it there and clear config cache:
        php artisan config:clear
        
    • Note this is a dependency-side flag, not a filament-mail flag — don't go hunting in config/filament-mail.php for it.
  2. Historical Sends Don't Appear as Campaigns

    • Grouping is by mail tag, so any email sent before you started tagging has no campaign to belong to. Expect a gap between the Analytics tab (all-time) and the Campaigns page (tagged traffic only). Backfill tags only if the underlying records actually store one.
  3. Migration Conflicts

    • If using laravel-mail, ensure the templates and mailables tables are not duplicated. Run:
      php artisan vendor:publish --tag="laravel-mail-migrations" --force
      
      before migrating.
  4. Template Caching

    • Clear the view cache after editing templates in the UI:
      php artisan view:clear
      
  5. Queue Stuck Emails

    • Monitor queued emails in the Logs tab. Restart the queue worker if emails are stuck:
      php artisan queue:restart
      
  6. Multi-Locale Sync

    • Ensure all locales are defined in config/app.php under locales. Missing locales may break template rendering.

Debugging

  • Log Inspection: Use the Logs tab to filter emails by status (sent, failed, queued).
  • Template Errors: Check the storage/logs/laravel-mail.log for rendering errors.
  • Event Debugging: Temporarily disable tracking events in config/filament-mail.php:
    'tracking' => [
        'events' => false,
    ],
    
    Remember that disabling tracking events also blanks out campaign rates — the Campaigns page reads the same events, so don't debug "zero opens" with tracking switched off.
  • Campaign Rate Sanity Checks (new page, most common confusions):
    • Click-to-open is derived, not stored. It's clicks ÷ opens, so it can exceed 100% when a link is clicked multiple times or when opens are undercounted (image-blocking clients). Treat it as a relative signal, not a hard metric.
    • Opens are inflated by proxy prefetching (Apple Mail Privacy Protection, some corporate scanners). Compare campaigns against each other rather than against an absolute target.
    • Complaint and bounce rates need volume. A campaign with 40 sends will show alarming percentages from a single event; don't act on it.
    • A missing link in "most clicked" usually means the URL wasn't rewritten — check that the link is a real <a href> in the rendered HTML, not injected by JS after load.
    • Rates are per campaign (tag), not per template or per locale. If you send the same template in en and pt, split them into separate tags if you want to compare them.

Extension Points

  1. Custom Fields

    • Extend the template editor by adding custom field types (e.g., for dynamic content):
      // app/Providers/FilamentMailServiceProvider.php
      FilamentMail::registerTemplateField(
          'dynamic_content',
          \JeffersonGoncalves\FilamentMail\Fields\DynamicContentField::class
      );
      
  2. API Access

    • Expose email endpoints via Filament’s API:
      // routes/api.php
      Route::middleware('auth:sanctum')->post('/send-mail', [\App\Http\Controllers\MailController::class, 'send']);
      
    • If you expose sending over an API, require a campaign/tag field in the request payload — otherwise API-triggered sends silently fall outside the Campaigns page.
  3. Webhook Integration

    • Listen for external webhooks (e.g., Mailgun, SendGrid) to update Filament Mail’s tracking:
      // app/Providers/EventServiceProvider.php
      protected $listen = [
          \JeffersonGoncalves\LaravelMail\Events\MailOpened::class => [
              \App\Listeners\UpdateTracking::class,
          ],
      ];
      
    • Campaign accuracy depends on this working. Bounces and complaints, in particular, usually arrive only via provider webhooks. If webhooks are misconfigured you'll see healthy-looking delivery rates and a permanent 0% complaint rate on the Campaigns page — an easy false positive.
  4. Bulk Actions

    • Add bulk suppression or resend functionality to the Logs table:
      // app/Providers/FilamentMailServiceProvider.php
      FilamentMail::tableActions([
          Tables\Actions\BulkAction::make('suppress')
              ->action(function (Collection $records) {
                  $records->each->suppress();
              }),
      ]);
      

Config Quirks

  • Default Locale Fallback: Set a fallback locale in config/filament-mail.php:
    'locales' => [
        'fallback' => 'en',
    ],
    
  • Asset Paths: Customize the asset path if using a CDN:
    'assets' => [
        'path' => 'cdn.example.com/storage/filament-mail',
    ],
    
  • Two Configs, Two Places: config/filament-mail.php controls the UI; campaign capture itself is configured in laravel-mail. When the Campaigns page misbehaves, check laravel-mail first — and remember php artisan config:clear after toggling either.
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.
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core