Weave Code
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

Laravel Mail Preview Laravel Package

spatie/laravel-mail-preview

Laravel mail transport to preview sent emails locally. Adds an in-browser overlay with a link to the last sent message, and lets you view rendered mail content in the browser. Ideal for development/testing; avoid in production.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the package:
    composer require spatie/laravel-mail-preview
    
  2. Configure the mail transport in config/mail.php:
    'mailers' => [
        'smtp' => [
            'transport' => 'preview',
            // ... other SMTP config
        ],
    ],
    
  3. Add middleware to app/Http/Kernel.php:
    protected $middlewareGroups = [
        'web' => [
            // ... other middleware
            \Spatie\MailPreview\Http\Middleware\AddMailPreviewOverlayToResponse::class,
        ],
    ];
    
  4. Register the preview route in routes/web.php:
    Route::mailPreview(); // Default: `/spatie-mail-preview`
    

First Use Case

Send a test email via a Mailable:

Mail::to('test@example.com')->send(new TestEmail());
  • A preview overlay will appear in your browser with a link to the generated HTML/EML files.
  • Files are stored in storage/email-previews with names like: 1712345678_test@example.com_subject.html.

Implementation Patterns

Workflow: Local Email Development

  1. Switch to Preview Transport: Use preview transport in config/mail.php for local testing.
  2. Send Emails: Trigger emails via Mailables or Mail::send().
  3. Inspect Previews:
    • Open the overlay link to view the last sent email.
    • Access /spatie-mail-preview to browse all stored emails.
  4. Test Assertions: Use SentMails facade in tests:
    SentMails::assertLastContains('Expected text');
    SentMails::assertSent(fn(SentMail $mail) => $mail->hasTo('test@example.com'));
    

Integration Tips

  • Conditional Activation: Disable in production by setting 'enabled' => env('APP_DEBUG') in config/mail-preview.php.
  • Custom Storage: Override storage_path to use a different directory:
    'storage_path' => storage_path('custom-email-previews'),
    
  • Event Listeners: Listen for MailStoredEvent to log or process emails:
    Event::listen(MailStoredEvent::class, function ($event) {
        Log::info('Email saved:', [
            'html' => $event->pathToHtmlVersion,
            'eml' => $event->pathToEmlVersion,
        ]);
    });
    

Testing Patterns

  • Assert Email Content:
    SentMails::assertCount(1);
    SentMails::last()->assertSubjectContains('Welcome');
    
  • Mock External Services: Combine with Mail::fake() for unit tests, then use SentMails for assertions:
    Mail::fake();
    $this->post('/send-email');
    SentMails::assertSent(fn(SentMail $mail) => $mail->bodyContains('Success'));
    

Gotchas and Tips

Pitfalls

  1. Debug Mode Dependency: The overlay and storage are disabled when APP_DEBUG=false. Ensure 'enabled' => env('APP_DEBUG') in config.
  2. File Naming Conflicts: Customize filename_date_format (e.g., 'Uu') to avoid collisions with identical subjects/recipients.
  3. Middleware Placement: Add the middleware after web middleware (e.g., auth) to avoid blocking the overlay for unauthenticated users.

Debugging

  • Missing Overlay: Verify:
    • Middleware is registered in Kernel.php.
    • Route mailPreview() is added to web.php.
    • APP_DEBUG=true in .env.
  • Empty Storage Directory: Check storage_path in config/mail-preview.php and permissions:
    mkdir -p storage/email-previews && chmod -R 775 storage/email-previews
    
  • Assertion Failures: Use SentMails::all() to inspect stored emails:
    dd(SentMails::all()->first()->body());
    

Extension Points

  1. Custom Views: Publish and modify views:
    php artisan vendor:publish --tag=mail-preview-views
    
    Override resources/views/vendor/mail-preview/overlay.blade.php or preview.blade.php.
  2. Event Handling: Extend MailStoredEvent to add metadata:
    Event::listen(MailStoredEvent::class, function ($event) {
        $event->message->getHeaders()->addTextHeader('X-Custom-ID', '123');
    });
    
  3. API Endpoints: Build a custom API route to fetch emails:
    Route::get('/api/emails', function () {
        return SentMails::all()->map(fn(SentMail $mail) => [
            'subject' => $mail->subject(),
            'url' => route('mail.preview', $mail->filename()),
        ]);
    });
    

Performance Tips

  • Cleanup Old Files: Use Laravel’s storage:link and schedule cleanup via Artisan::call('mail:cleanup'):
    // In a console command
    $files = Storage::files('email-previews');
    foreach ($files as $file) {
        if (now()->diffInSeconds($file->lastModified()) > config('mail-preview.maximum_lifetime_in_seconds')) {
            Storage::delete($file);
        }
    }
    
  • Disable Overlay in CI: Set MAIL_PREVIEW_SHOW_LINK=false in .env for faster CI runs.

Laravel-Specific Quirks

  • Queue vs. Immediate: Emails sent via queues may not trigger the overlay immediately. Use Mail::to()->send() directly in tests.
  • Markdown Emails: Ensure Blade components in Markdown emails are rendered by using ->with() or ->render() in Mailables:
    $this->markdown('emails.test')->with(['data' => $data]);
    
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.
codraw/framework-extra-bundle
codraw/messenger
codraw/security
codraw/mailer
codraw/contracts
codraw/profiling
codraw/dependency-injection
codraw/tester
codraw/core
nexmo/api-specification
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony