mailhive / mailhive-php
The official PHP SDK for Mailhive Send, with a Laravel mail transport.
Requires
- php: ^8.1
- ext-curl: *
- ext-json: *
Requires (Dev)
- orchestra/testbench: ^9.0 || ^10.0 || ^11.0
- phpunit/phpunit: ^10.5 || ^11.0
- symfony/mailer: ^6.4 || ^7.0
Suggests
- symfony/mailer: For the Laravel/Symfony mail transport (Laravel includes it)
Provides
None
Conflicts
None
Replaces
None
This package is not auto-updated.
Last update: 2026-09-29 21:45:07 UTC
README
The official PHP SDK for Mailhive Send. It needs PHP 8.1+ and only ext-curl and ext-json. It includes a Laravel mail driver.
composer require mailhive/mailhive-php
Send an email
use Mailhive\Mailhive; $mailhive = new Mailhive(); // reads MAILHIVE_API_KEY $email = $mailhive->emails->send([ 'from' => 'Acme <hello@acme.com>', 'to' => 'ada@example.com', 'subject' => 'Your receipt', 'html' => '<p>Thanks for your order.</p>', ]); echo $email['id'];
The keys match the API reference exactly: cc, bcc, reply_to, headers, tags, template_id, variables and attachments.
An attachment's content is the raw file, which is encoded for you. Use content_base64 if your data is already base64:
'attachments' => [ ['filename' => 'invoice.pdf', 'content' => file_get_contents('invoice.pdf'), 'content_type' => 'application/pdf'], ],
$mailhive->emails->sendBatch([$email1, $email2]); // up to 100; all accepted or none $mailhive->emails->get($id); // ['status' => 'delivered', …]
Laravel
The package registers itself. Add the key and the mailer:
// config/services.php 'mailhive' => ['key' => env('MAILHIVE_API_KEY')], // config/mail.php, under 'mailers' 'mailhive' => ['transport' => 'mailhive'],
MAIL_MAILER=mailhive MAILHIVE_API_KEY=mhs_…
Every Mailable and notification then sends through Mailhive, including attachments, cc, bcc and Reply-To. A Mailable's tags and metadata become Mailhive tags. To make a send safe to repeat, add an X-Mailhive-Idempotency-Key header:
public function headers(): Headers { return new Headers(text: ['X-Mailhive-Idempotency-Key' => "order-{$this->order->id}-receipt"]); }
You can also type-hint the client anywhere: public function __construct(private \Mailhive\Mailhive $mailhive) {}.
Plain Symfony apps can use new \Mailhive\Laravel\MailhiveTransport($client) as a Symfony Mailer transport.
Retries and idempotency
Every send carries an Idempotency-Key. Retries reuse it, so a retry never sends twice.
- Retried (up to 2 times, then configurable): network errors, timeouts, 5xx responses, and
429 rate_limitedafter theRetry-Afterdelay. - Not retried: a used-up allowance and invalid requests.
To stay safe across restarts, pass your own key:
$mailhive->emails->send($email, ['idempotency_key' => "order-{$order->id}-receipt"]);
Errors
use Mailhive\Exception\RateLimitException; use Mailhive\Exception\ValidationException; try { $mailhive->emails->send($email); } catch (ValidationException $e) { echo $e->errorCode(), $e->getMessage(), json_encode($e->details()), $e->requestId(); } catch (RateLimitException $e) { // $e->errorCode() === 'monthly_quota_reached', or $e->retryAfter() }
| Exception | Status |
|---|---|
AuthenticationException |
401 |
BillingException |
402 |
PermissionException |
403 |
NotFoundException |
404 |
ConflictException |
409 |
ValidationException |
422 |
RateLimitException |
429 |
ApiException |
other statuses, and the base class of all of the above |
ConnectionException |
no response |
All of them extend MailhiveException. Use errorCode() for Mailhive's code: PHP reserves getCode() for the HTTP status.
Webhooks
use Mailhive\Exception\WebhookVerificationException; use Mailhive\Webhook; try { $event = Webhook::verify( file_get_contents('php://input'), // Laravel: $request->getContent() $_SERVER['HTTP_MAILHIVE_SIGNATURE'] ?? null, // Laravel: $request->header('Mailhive-Signature') getenv('MAILHIVE_WEBHOOK_SECRET'), ); } catch (WebhookVerificationException $e) { http_response_code(400); exit; }
Options
new Mailhive('mhs_…', [ 'base_url' => 'https://api-beta.mailhive.africa/v1', // default: MAILHIVE_BASE_URL, then production 'timeout' => 30.0, 'max_retries' => 2, ]);
Test keys (mhs_test_…) work unchanged: delivery is simulated and nothing is billed.
This package is published from the mailhive-sdks monorepo. Please open issues and pull requests there.
Releasing (maintainers)
- Bump
Mailhive::VERSION, then merge tomainin mailhive-sdks. - Push the tag
php-vX.Y.Zthere. - The
split-phpworkflow mirrorsphp/to Naszat/mailhive-php and tags itvX.Y.Z. Packagist then picks it up.
Without the PHP_MIRROR_DEPLOY_KEY secret, run the same steps from a checkout of main:
git subtree split --prefix php -b php-split
git push git@github.com:Naszat/mailhive-php.git php-split:main
git tag vX.Y.Z php-split && git push git@github.com:Naszat/mailhive-php.git vX.Y.Z