Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## [Unreleased]
- Add Stats API with get, byDomain, byCategory, byEmailServiceProvider, byDate endpoints

## [3.9.1] - 2025-10-27
- Improve README

Expand Down
97 changes: 97 additions & 0 deletions examples/sending/stats.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
<?php

use Mailtrap\Config;
use Mailtrap\Helper\ResponseHelper;
use Mailtrap\MailtrapSendingClient;

require __DIR__ . '/../../vendor/autoload.php';

$accountId = (int) $_ENV['MAILTRAP_ACCOUNT_ID'];
$config = new Config($_ENV['MAILTRAP_API_KEY']); #your API token from here https://mailtrap.io/api-tokens
$stats = (new MailtrapSendingClient($config))->stats($accountId);

/**
* Get aggregated sending stats.
*
* GET https://mailtrap.io/api/accounts/{account_id}/stats
*/
try {
$response = $stats->get('2026-01-01', '2026-01-31');

// print the response body (array)
var_dump(ResponseHelper::toArray($response));
} catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), PHP_EOL;
}

/**
* Get aggregated sending stats with filters.
*
* GET https://mailtrap.io/api/accounts/{account_id}/stats
*/
try {
$response = $stats->get(
'2026-01-01',
'2026-01-31',
sendingDomainIds: [1, 2],
sendingStreams: ['transactional'],
categories: ['Transactional', 'Marketing'],
emailServiceProviders: ['Gmail', 'Yahoo']
);

var_dump(ResponseHelper::toArray($response));
} catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), PHP_EOL;
}

/**
* Get sending stats grouped by domains.
*
* GET https://mailtrap.io/api/accounts/{account_id}/stats/domains
*/
try {
$response = $stats->byDomain('2026-01-01', '2026-01-31');

var_dump(ResponseHelper::toArray($response));
} catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), PHP_EOL;
}

/**
* Get sending stats grouped by categories.
*
* GET https://mailtrap.io/api/accounts/{account_id}/stats/categories
*/
try {
$response = $stats->byCategory('2026-01-01', '2026-01-31');

var_dump(ResponseHelper::toArray($response));
} catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), PHP_EOL;
}

/**
* Get sending stats grouped by email service providers.
*
* GET https://mailtrap.io/api/accounts/{account_id}/stats/email_service_providers
*/
try {
$response = $stats->byEmailServiceProvider('2026-01-01', '2026-01-31');

var_dump(ResponseHelper::toArray($response));
} catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), PHP_EOL;
}

/**
* Get sending stats grouped by date.
*
* GET https://mailtrap.io/api/accounts/{account_id}/stats/date
*/
try {
$response = $stats->byDate('2026-01-01', '2026-01-31');

var_dump(ResponseHelper::toArray($response));
} catch (Exception $e) {
echo 'Caught exception: ', $e->getMessage(), PHP_EOL;
}
192 changes: 192 additions & 0 deletions src/Api/Sending/Stats.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
<?php

declare(strict_types=1);

namespace Mailtrap\Api\Sending;

use Mailtrap\Api\AbstractApi;
use Mailtrap\ConfigInterface;
use Psr\Http\Message\ResponseInterface;

/**
* Class Stats
*/
class Stats extends AbstractApi implements SendingInterface
{
public function __construct(ConfigInterface $config, private int $accountId)
{
parent::__construct($config);
}
Comment on lines +16 to +19
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fail fast for invalid account IDs.

A non-positive account ID currently passes through and only fails at request time. Validate it in the constructor to catch misuse earlier.

Proposed fix
 public function __construct(ConfigInterface $config, private int $accountId)
 {
+    if ($accountId <= 0) {
+        throw new \InvalidArgumentException('Account ID must be greater than 0.');
+    }
+
     parent::__construct($config);
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
public function __construct(ConfigInterface $config, private int $accountId)
{
parent::__construct($config);
}
public function __construct(ConfigInterface $config, private int $accountId)
{
if ($accountId <= 0) {
throw new \InvalidArgumentException('Account ID must be greater than 0.');
}
parent::__construct($config);
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/Api/Sending/Stats.php` around lines 16 - 19, Validate the injected
accountId in the Stats::__construct and throw an InvalidArgumentException if
it's not a positive integer (<= 0) so misuse is caught immediately; add the
check at the start of the constructor (before proceeding with
parent::__construct) and use a clear error message mentioning the invalid
$accountId and the Stats class.


/**
* Get aggregated sending stats.
*
* @param string $startDate
* @param string $endDate
* @param array $sendingDomainIds
* @param array $sendingStreams
* @param array $categories
* @param array $emailServiceProviders
*
* @return ResponseInterface
*/
public function get(
string $startDate,
string $endDate,
array $sendingDomainIds = [],
array $sendingStreams = [],
array $categories = [],
array $emailServiceProviders = []
): ResponseInterface {
return $this->handleResponse($this->httpGet(
$this->getBasePath(),
$this->buildQueryParams($startDate, $endDate, $sendingDomainIds, $sendingStreams, $categories, $emailServiceProviders)
));
}

/**
* Get sending stats grouped by domains.
*
* @param string $startDate
* @param string $endDate
* @param array $sendingDomainIds
* @param array $sendingStreams
* @param array $categories
* @param array $emailServiceProviders
*
* @return ResponseInterface
*/
public function byDomain(
string $startDate,
string $endDate,
array $sendingDomainIds = [],
array $sendingStreams = [],
array $categories = [],
array $emailServiceProviders = []
): ResponseInterface {
return $this->handleResponse($this->httpGet(
$this->getBasePath() . '/domains',
$this->buildQueryParams($startDate, $endDate, $sendingDomainIds, $sendingStreams, $categories, $emailServiceProviders)
));
}

/**
* Get sending stats grouped by categories.
*
* @param string $startDate
* @param string $endDate
* @param array $sendingDomainIds
* @param array $sendingStreams
* @param array $categories
* @param array $emailServiceProviders
*
* @return ResponseInterface
*/
public function byCategory(
string $startDate,
string $endDate,
array $sendingDomainIds = [],
array $sendingStreams = [],
array $categories = [],
array $emailServiceProviders = []
): ResponseInterface {
return $this->handleResponse($this->httpGet(
$this->getBasePath() . '/categories',
$this->buildQueryParams($startDate, $endDate, $sendingDomainIds, $sendingStreams, $categories, $emailServiceProviders)
));
}

/**
* Get sending stats grouped by email service providers.
*
* @param string $startDate
* @param string $endDate
* @param array $sendingDomainIds
* @param array $sendingStreams
* @param array $categories
* @param array $emailServiceProviders
*
* @return ResponseInterface
*/
public function byEmailServiceProvider(
string $startDate,
string $endDate,
array $sendingDomainIds = [],
array $sendingStreams = [],
array $categories = [],
array $emailServiceProviders = []
): ResponseInterface {
return $this->handleResponse($this->httpGet(
$this->getBasePath() . '/email_service_providers',
$this->buildQueryParams($startDate, $endDate, $sendingDomainIds, $sendingStreams, $categories, $emailServiceProviders)
));
}

/**
* Get sending stats grouped by date.
*
* @param string $startDate
* @param string $endDate
* @param array $sendingDomainIds
* @param array $sendingStreams
* @param array $categories
* @param array $emailServiceProviders
*
* @return ResponseInterface
*/
public function byDate(
string $startDate,
string $endDate,
array $sendingDomainIds = [],
array $sendingStreams = [],
array $categories = [],
array $emailServiceProviders = []
): ResponseInterface {
return $this->handleResponse($this->httpGet(
$this->getBasePath() . '/date',
$this->buildQueryParams($startDate, $endDate, $sendingDomainIds, $sendingStreams, $categories, $emailServiceProviders)
));
}

public function getAccountId(): int
{
return $this->accountId;
}

private function getBasePath(): string
{
return sprintf('%s/api/accounts/%s/stats', $this->getHost(), $this->getAccountId());
}

private function buildQueryParams(
string $startDate,
string $endDate,
array $sendingDomainIds,
array $sendingStreams,
array $categories,
array $emailServiceProviders
): array {
$params = [
'start_date' => $startDate,
'end_date' => $endDate,
];

if (count($sendingDomainIds) > 0) {
$params['sending_domain_ids'] = $sendingDomainIds;
}

if (count($sendingStreams) > 0) {
$params['sending_streams'] = $sendingStreams;
}

if (count($categories) > 0) {
$params['categories'] = $categories;
}

if (count($emailServiceProviders) > 0) {
$params['email_service_providers'] = $emailServiceProviders;
}

return $params;
}
}
2 changes: 2 additions & 0 deletions src/MailtrapSendingClient.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
* @method Api\Sending\Emails emails()
* @method Api\Sending\Suppression suppressions(int $accountId)
* @method Api\Sending\Domain domains(int $accountId)
* @method Api\Sending\Stats stats(int $accountId)
*
* Class MailtrapSendingClient
*/
Expand All @@ -17,5 +18,6 @@ final class MailtrapSendingClient extends AbstractMailtrapClient implements Emai
'emails' => Api\Sending\Emails::class,
'suppressions' => Api\Sending\Suppression::class,
'domains' => Api\Sending\Domain::class,
'stats' => Api\Sending\Stats::class,
];
}
Loading
Loading