Integration Guide

SMTP testing with Laravel

Go beyond Mail::fake(). Capture real SMTP emails with full HTML preview, spam scoring, and header inspection.

Why use MailHog instead of Mail::fake()?

Laravel's Mail::fake() is great for unit testing — it lets you assert that a Mailable was dispatched. But it doesn't show you what the email looks like. You can't check HTML rendering, spam scores, or header correctness with Mail::fake().

MailHog captures the actual SMTP output — the same bytes that would reach a real mail server. You see the rendered HTML, check spam scoring, and inspect every header. This is essential for catching layout bugs, deliverability issues, and MIME encoding problems.

Quickstart: Laravel .env configuration

# .env (local development)
MAIL_MAILER=smtp
MAIL_HOST=smtp.mailhog.site
MAIL_PORT=2525
MAIL_USERNAME=your-inbox-username
MAIL_PASSWORD=your-inbox-password
MAIL_ENCRYPTION=null
MAIL_FROM_ADDRESS="noreply@yourapp.com"
MAIL_FROM_NAME="Your App"

That's it. Every email Laravel sends — Mailables, Notifications, password resets — will be captured in your MailHog inbox.

Test it with artisan tinker

php artisan tinker

>>> Mail::raw('Hello from Laravel!', function ($m) {
...     $m->to('test@example.com')
...       ->subject('Test from Laravel');
... });

// Check MailHog dashboard — email appears instantly ✅

Integration testing with PHPUnit

public function test_password_reset_sends_email()
{
    $this->post('/forgot-password', [
        'email' => 'user@test.com',
    ]);

    // Query MailHog API
    $response = Http::withHeaders([
        'X-API-Key' => config('services.mailhog.api_key'),
    ])->get(config('services.mailhog.url') . '/api/v1/inbox/' . 
        config('services.mailhog.inbox_id') . '/messages', [
        'to' => 'user@test.com',
    ]);

    $emails = $response->json('data');
    $this->assertNotEmpty($emails);
    $this->assertStringContains('Reset', $emails[0]['subject']);
}

Common pitfalls

  • Setting MAIL_ENCRYPTION=tls with port 2525 — use null instead
  • Forgetting to clear the config cache after changing .env: php artisan config:clear
  • Using MAIL_MAILER=log in CI instead of smtp — you miss real SMTP issues
  • Not testing queued emails — make sure your test runs the queue

Related guides

Start testing Laravel emails

Get SMTP credentials in 60 seconds.

Start free →