MailSlurp logo

examples

Receive Email in PHP with MailSlurp (PHPUnit + Real Inboxes)

Learn how to send and receive real emails in PHP tests using MailSlurp. Create inboxes, wait for delivery, and assert content reliably in PHPUnit.

If you need reliable email assertions in PHP tests, treat email as an external system with deterministic checks.

This guide shows a practical pattern:

  1. create test inboxes with the API
  2. send an email between those inboxes
  3. wait for delivery
  4. assert subject, body, sender, recipient, and extracted tokens

Why API-based inbox testing instead of local SMTP only

Local SMTP traps are useful for basic development, but API-driven inboxes are usually better for CI and integration tests because you can:

  • create isolated inboxes per test run
  • wait for specific messages instead of sleeping
  • parse and assert dynamic content (codes, links, IDs)
  • run the same flow in local, CI, and shared environments

Prerequisites

Set your API key as an environment variable:

export MAILSLURP_API_KEY="your-api-key"

Install dependencies

composer require --dev mailslurp/mailslurp-client-php phpunit/phpunit

End-to-end PHPUnit example

<?php
require_once __DIR__ . '/vendor/autoload.php';

use PHPUnit\Framework\TestCase;

final class EmailFlowTest extends TestCase
{
    private function config(): MailSlurp\Configuration
    {
        $apiKey = getenv('MAILSLURP_API_KEY');
        if (!$apiKey) {
            throw new RuntimeException('MAILSLURP_API_KEY is not set');
        }

        return MailSlurp\Configuration::getDefaultConfiguration()
            ->setApiKey('x-api-key', $apiKey);
    }

    public function test_can_send_and_receive_email_between_two_inboxes(): void
    {
        $inboxApi = new MailSlurp\Apis\InboxControllerApi(null, $this->config());
        $waitApi = new MailSlurp\Apis\WaitForControllerApi(null, $this->config());

        $sender = $inboxApi->createInbox();
        $recipient = $inboxApi->createInbox();

        $sendOptions = new MailSlurp\Models\SendEmailOptions();
        $sendOptions->setTo([$recipient->getEmailAddress()]);
        $sendOptions->setSubject('Verify your account');
        $sendOptions->setBody('Your verification code is ABC-123');

        $inboxApi->sendEmail($sender->getId(), $sendOptions);

        $email = $waitApi->waitForLatestEmail(
            $recipient->getId(),
            30000, // timeout ms
            true   // unreadOnly
        );

        $this->assertEquals($sender->getEmailAddress(), $email->getFrom());
        $this->assertEquals($recipient->getEmailAddress(), $email->getTo()[0]);
        $this->assertEquals('Verify your account', $email->getSubject());
        $this->assertStringContainsString('verification code', $email->getBody());

        preg_match('/code is ([A-Z]{3}-[0-9]{3})/', $email->getBody(), $matches);
        $this->assertEquals('ABC-123', $matches[1]);
    }
}

Pattern for Laravel projects

For Laravel, keep transport and assertions separate:

  • keep your app sending through your normal mail channel
  • use MailSlurp in tests to observe what users would actually receive
  • assert business-critical payloads (links, codes, locale strings, legal footer)

This avoids test-only mail internals leaking into production code.

Hardening checklist for CI

  • create fresh inboxes per test to avoid cross-test contamination
  • use explicit wait conditions instead of sleep() calls
  • keep message assertions focused on business outcomes
  • mask secrets and rotate API keys regularly

Next guides