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

Mailer Test Laravel Package

zenstruck/mailer-test

Opinionated helpers to test emails sent with symfony/mailer. Use InteractsWithMailer in KernelTestCase/WebTestCase for fluent assertions like assertNoEmailSent, assertSentEmailCount, and inspect messages with TestEmail (subject, recipients, body, attachments).

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require --dev zenstruck/mailer-test
    

    Enable the bundle in your tests/config/packages/test/_mailer.yaml:

    imports:
        - { resource: "@ZenstruckMailerTestBundle/Resources/config/test.yaml" }
    
  2. First Test Case: Extend KernelTestCase or WebTestCase and use the InteractsWithMailer trait:

    use Zenstruck\Mailer\Test\InteractsWithMailer;
    
    class EmailTest extends KernelTestCase
    {
        use InteractsWithMailer;
    
        public function test_basic_email_sent()
        {
            Mailer::to('user@example.com')->send(new YourEmail());
    
            $this->mailer()->assertEmailSentTo('user@example.com');
        }
    }
    

First Use Case: Verify Email Content

public function test_email_content()
{
    Mailer::to('user@example.com')->send(new YourEmail());

    $this->mailer()->assertEmailSentTo('user@example.com', function(TestEmail $email) {
        $email
            ->assertSubject('Welcome!')
            ->assertTextContains('Thank you for registering')
            ->assertHasFile('welcome.pdf');
    });
}

Implementation Patterns

Core Workflow: Assertion-Based Testing

  1. Trigger Email Sending:

    $this->client->request('POST', '/register', [
        'email' => 'user@example.com'
    ]);
    
  2. Assert Email Sent:

    $this->mailer()->assertEmailSentTo('user@example.com');
    
  3. Deep Assertions:

    $this->mailer()->assertEmailSentTo('user@example.com', function(TestEmail $email) {
        $email
            ->assertSubjectContains('Registration')
            ->assertFrom('no-reply@example.com')
            ->assertHasTag('welcome');
    });
    

Filtering Sent Emails

// Filter by subject
$sentEmails = $this->mailer()->sentEmails()
    ->whereSubjectContains('Password')
    ->assertCount(1);

// Filter by recipient
$sentEmails = $this->mailer()->sentEmails()
    ->whereTo('admin@example.com')
    ->each(function(TestEmail $email) {
        $email->assertSubject('Admin Notification');
    });

Integration with Browser Testing

// Using MailerComponent
$browser->withProfiling()
    ->visit('/forgot-password')
    ->use(function(MailerComponent $mailer) {
        $mailer->assertEmailSentTo('user@example.com');
    });

Custom TestEmail Extensions

class AppTestEmail extends TestEmail
{
    public function assertHasCustomHeader(string $header, string $value): self
    {
        return $this->assertHeader($header, $value);
    }
}

Gotchas and Tips

Common Pitfalls

  1. Kernel Reset: Emails persist between kernel reboots. Always reset after tests:

    $this->mailer()->reset();
    
  2. Profiler Dependency: Browser-based assertions require the profiler. Enable it explicitly:

    $browser->withProfiling();
    
  3. Type Safety: Custom TestEmail classes must be explicitly type-hinted in callbacks:

    // Wrong (uses default TestEmail)
    $this->mailer()->assertEmailSentTo('user@example.com', function($email) { ... });
    
    // Correct
    $this->mailer()->assertEmailSentTo('user@example.com', function(AppTestEmail $email) { ... });
    

Debugging Tips

  • Dump Emails:
    $this->mailer()->sentEmails()->dump();
    
  • Verify Headers:
    $email->getHeaders()->get('X-Custom-Header');
    

Configuration Quirks

  • Symfony 5.2+: Profiler is required for browser assertions.
  • PHP 8+: Required for full functionality (static return types, etc.).
  • Symfony 6+: Supports signed emails out of the box.

Extension Points

  1. Custom Assertions: Extend TestEmail to add domain-specific checks (e.g., assertHasPostmarkTag).
  2. Global Reset: Override reset() in a base test case for shared test suites.
  3. Browser Integration: Use MailerExtension to embed assertions directly into custom browsers.

Performance Note

  • Avoid sentEmails()->all() in large test suites. Pre-filter with where() instead.
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.
cuci/prototurk-sdk-symfony
clementtalleu/easyadmin-markdown-bundle
codeflextech/permission-manager
karnoweb/livewire-datepicker
sayedenam/sayed-dashboard
milito/query-filter
apiboxsym/user-bundle
apiboxsym/health-check-bundle
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager