PHPackages                             mailcapture/mailcapture-php - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Testing &amp; Quality](/categories/testing)
4. /
5. mailcapture/mailcapture-php

ActiveLibrary[Testing &amp; Quality](/categories/testing)

mailcapture/mailcapture-php
===========================

Official PHP SDK for the MailCapture email testing API

v1.0.2(1mo ago)00MITPHPPHP &gt;=8.1

Since Jun 23Pushed 3mo agoCompare

[ Source](https://github.com/MailCapture/mailcapture-php)[ Packagist](https://packagist.org/packages/mailcapture/mailcapture-php)[ Docs](https://mailcapture.app)[ RSS](/packages/mailcapture-mailcapture-php/feed)WikiDiscussions main Synced 2w ago

READMEChangelogDependencies (2)Versions (3)Used By (0)

mailcapture-php
===============

[](#mailcapture-php)

Official PHP SDK for [MailCapture](https://mailcapture.app) — a real email capture API for integration testing OTP codes, verification links, and other transactional emails.

Requirements
------------

[](#requirements)

- PHP 8.1+
- Guzzle 7 (`guzzlehttp/guzzle`)

Installation
------------

[](#installation)

```
composer require mailcapture/mailcapture-php
```

Quick start
-----------

[](#quick-start)

```
use MailCapture\MailCapture;

$mc = new MailCapture($_ENV['MAILCAPTURE_API_KEY']);
$mc->ping();  // validates key, caches username

// In your test:
$mc->delete('signup');
$yourApp->register($mc->address('signup'));   // e.g. "alice-signup@mailcapture.app"
$email = $mc->waitFor('signup', timeout: 15.0);

echo $email->subject;   // "Verify your account"
echo $email->otp;       // "123456" — extracted automatically
```

The pattern for integration tests
---------------------------------

[](#the-pattern-for-integration-tests)

```
use MailCapture\MailCapture;
use MailCapture\Model\Capture;
use PHPUnit\Framework\TestCase;

class UserRegistrationTest extends TestCase
{
    private static MailCapture $mc;

    public static function setUpBeforeClass(): void
    {
        self::$mc = new MailCapture($_ENV['MAILCAPTURE_API_KEY']);
        self::$mc->ping();
    }

    protected function setUp(): void
    {
        self::$mc->delete('signup');   // clean inbox before every test
    }

    public function testUserReceivesVerificationEmail(): void
    {
        $inbox = self::$mc->inbox('signup');

        $this->app->register($inbox->getAddress()); // "alice-signup@mailcapture.app"

        $email = $inbox->waitFor(timeout: 10.0);

        $this->assertSame('Verify your account', $email->subject);
        $this->assertMatchesRegularExpression('/^\d{6}$/', $email->otp);
        $this->assertLessThan(5000, $email->latencyMs);
    }
}
```

API reference
-------------

[](#api-reference)

### `new MailCapture($apiKey, ...)`

[](#new-mailcaptureapikey-)

```
$mc = new MailCapture(
    apiKey: $_ENV['MAILCAPTURE_API_KEY'],
    baseUrl: 'http://localhost:3002',   // override for local dev (default: https://mailcapture.app)
    requestTimeout: 15.0,              // seconds, default 10.0
    username: 'alice',                 // pre-set to skip ping() (optional)
);
```

---

### `ping()` → `PingResult`

[](#ping--pingresult)

Validates your API key and returns your address template. Caches your `username` so `address()` works without a network call.

```
$result = $mc->ping();
echo $result->username;          // "alice"
echo $result->addressTemplate;   // "alice-{tag}@mailcapture.app"
echo $result->example;           // "alice-signup@mailcapture.app"
```

---

### `waitFor(tag, timeout, pollTimeout, after)` → `Capture`

[](#waitfortag-timeout-polltimeout-after--capture)

Long-polls the API and returns the first email captured for the given tag. The server holds the connection open — no busy-waiting.

```
// Named arguments (recommended)
$email = $mc->waitFor('signup', timeout: 15.0);

// Full options
$email = $mc->waitFor(
    tag: 'signup',
    timeout: 15.0,           // total seconds to wait (default 30)
    pollTimeout: 5,           // per-poll server timeout in seconds, max 30 (default 10)
    after: new DateTime('-30 seconds'),  // only captures after this time
);
```

Throws `MailCaptureTimeoutException` if no email arrives in time.

---

### `inbox(tag)` → `Inbox`

[](#inboxtag--inbox)

Returns a scoped `Inbox` for a tag. Keeps test code clean.

```
$inbox = $mc->inbox('password-reset');

$inbox->getAddress()                    // "alice-password-reset@mailcapture.app"
$inbox->waitFor(timeout: 10.0)          // Capture
$inbox->list(limit: 5)                  // CaptureList
$inbox->clear()                         // deletes all captures for this tag
```

---

### `address(tag)` → `string`

[](#addresstag--string)

Generates the capture email address synchronously. Requires `ping()` first (or `username` in the constructor).

```
$mc->ping();
echo $mc->address('signup');  // "alice-signup@mailcapture.app"
```

---

### `list(tag, limit, after)` → `CaptureList`

[](#listtag-limit-after--capturelist)

Lists recent captures (newest first).

```
$result = $mc->list(tag: 'signup', limit: 10);
foreach ($result->items as $email) {
    echo $email->subject . PHP_EOL;
}
```

---

### `get(captureId)` → `Capture`

[](#getcaptureid--capture)

Get a single capture by ID. Throws `MailCaptureNotFoundException` if not found.

---

### `delete(tag)` → `void`

[](#deletetag--void)

Deletes all captures for a tag. Use in `setUp()` for test isolation.

---

The `Capture` object
--------------------

[](#the-capture-object)

```
$email->id          // string — UUID
$email->tag         // string — e.g. "signup"
$email->subject     // string — email subject line
$email->otp         // ?string — extracted code, null if none detected
$email->bodyText    // ?string — plain-text body
$email->bodyHtml    // ?string — HTML body
$email->latencyMs   // int — send-to-capture time in ms
$email->status      // string — e.g. "captured"
$email->receivedAt  // string — ISO 8601 timestamp
```

The `otp` field is extracted automatically. If your OTP is embedded in a sentence, the service finds it for you.

---

Exception handling
------------------

[](#exception-handling)

All exceptions extend `MailCaptureException extends \RuntimeException` and have `getErrorCode()`.

```
use MailCapture\Exception\{
    MailCaptureAuthException,
    MailCaptureTimeoutException,
    MailCaptureNotFoundException,
    MailCaptureNetworkException,
};

try {
    $email = $mc->waitFor('signup', timeout: 10.0);
} catch (MailCaptureTimeoutException $e) {
    echo "Waited {$e->getWaitedSeconds()}s for tag: {$e->getTag()}" . PHP_EOL;
    echo "Did the email send? Check your email service logs." . PHP_EOL;
} catch (MailCaptureAuthException $e) {
    echo "Check your MAILCAPTURE_API_KEY environment variable." . PHP_EOL;
} catch (MailCaptureNetworkException $e) {
    echo "Network error: " . $e->getPrevious()?->getMessage() . PHP_EOL;
}
```

Exception`getErrorCode()`When`MailCaptureAuthException``UNAUTHORIZED`Invalid or revoked API key`MailCaptureTimeoutException``TIMEOUT``waitFor` exceeded timeout`MailCaptureNotFoundException``NOT_FOUND``get()` — capture not found`MailCaptureNetworkException``NETWORK_ERROR`Could not reach the API`MailCaptureApiException`variesUnexpected API error---

Testing with a mock HTTP client
-------------------------------

[](#testing-with-a-mock-http-client)

Inject a Guzzle mock client to test your code without hitting the real API:

```
use GuzzleHttp\Client;
use GuzzleHttp\Handler\MockHandler;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Psr7\Response;
use MailCapture\MailCapture;

$mock  = new MockHandler([
    new Response(200, ['Content-Type' => 'application/json'], json_encode([
        'items' => [[
            'id' => 'test-id', 'tag' => 'signup', 'subject' => 'Welcome',
            'otp' => '123456', 'body_text' => null, 'body_html' => null,
            'latency_ms' => 50, 'status' => 'captured',
            'received_at' => '2024-01-01T00:00:00+00:00',
        ]],
        'count' => 1,
        'next_after' => '2024-01-01T00:00:01+00:00',
    ])),
]);
$stack = HandlerStack::create($mock);
$mc    = new MailCapture('mc_testkey', httpClient: new Client(['handler' => $stack]));

$email = $mc->waitFor('signup', timeout: 5.0);
assert($email->otp === '123456');
```

---

Laravel / Symfony integration
-----------------------------

[](#laravel--symfony-integration)

```
// Laravel: AppServiceProvider
$this->app->singleton(MailCapture::class, fn() =>
    new MailCapture(config('services.mailcapture.key'))
);

// Symfony: services.yaml
services:
  MailCapture\MailCapture:
    arguments:
      $apiKey: '%env(MAILCAPTURE_API_KEY)%'
```

---

Local development
-----------------

[](#local-development)

```
$mc = new MailCapture($_ENV['MAILCAPTURE_API_KEY'], baseUrl: 'http://localhost:3002');
```

###  Health Score

36

—

LowBetter than 79% of packages

Maintenance87

Actively maintained with recent releases

Popularity0

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity43

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~10 days

Total

2

Last Release

34d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/4589530?v=4)[backupbrain](/maintainers/backupbrain)[@backupbrain](https://github.com/backupbrain)

---

Top Contributors

[![backupbrain](https://avatars.githubusercontent.com/u/4589530?v=4)](https://github.com/backupbrain "backupbrain (3 commits)")

---

Tags

testingotpemailintegration-testmailcapture

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/mailcapture-mailcapture-php/health.svg)

```
[![Health](https://phpackages.com/badges/mailcapture-mailcapture-php/health.svg)](https://phpackages.com/packages/mailcapture-mailcapture-php)
```

###  Alternatives

[aws/aws-sdk-php

AWS SDK for PHP - Use Amazon Web Services in your PHP project

6.2k555.0M2.8k](/packages/aws-aws-sdk-php)[neuron-core/neuron-ai

The PHP Agentic Framework.

2.0k832.6k51](/packages/neuron-core-neuron-ai)[tencentcloud/tencentcloud-sdk-php

TencentCloudApi php sdk

3661.3M49](/packages/tencentcloud-tencentcloud-sdk-php)[magento/magento2-functional-testing-framework

Magento2 Functional Testing Framework

15312.2M36](/packages/magento-magento2-functional-testing-framework)[tempest/framework

The PHP framework that gets out of your way.

2.3k37.6k19](/packages/tempest-framework)[eslazarev/wildberries-sdk

Wildberries OpenAPI clients (generated).

293.1k](/packages/eslazarev-wildberries-sdk)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
