knplabs/mailjet-api-php
A lightweight PHP wrapper for the Mailjet API from KNP Labs, offering straightforward access to Mailjet endpoints for sending email and managing contacts, lists, and campaigns. It suits PHP projects that need a simple, direct Mailjet integration without a large framework dependency.
First, verify this is still installable. The package is archived, last released in September 2015, and has very low adoption. Before wiring anything into an application, check its composer.json for the PHP constraint and autoload mapping:
composer require knplabs/mailjet-api-php
If Composer refuses due to an old PHP constraint, do not paper over it with --ignore-platform-reqs in production. Treat that as a signal to evaluate the official Mailjet SDK instead.
Where to look first:
README.md — the only reliable usage example. Since the repo is archived and has ~10 stars, there is effectively no community documentation; the source is the documentation.composer.json — namespace, autoload style (likely PSR-0 or early PSR-4), PHP version, cURL/ext dependencies.src/ — identify the entry-point client class and how it accepts credentials (constructor vs. setters), and what it returns (array, object, or raw JSON string).Credentials. You need a Mailjet API key and secret from the Mailjet dashboard (API Key Management). These are not the same as SMTP credentials. Put them in .env:
MAILJET_API_KEY=
MAILJET_API_SECRET=
First use case: send one transactional email and inspect the raw response. Adapt the class name and method signature to whatever the source actually exposes:
$client = new \Knp\Mailjet\Client(
config('services.mailjet.key'),
config('services.mailjet.secret')
);
$response = $client->post('send', [
'From' => ['Email' => '[email protected]', 'Name' => 'Example'],
'To' => [['Email' => '[email protected]', 'Name' => 'You']],
'Subject' => 'Test from the archived KNPLabs wrapper',
'TextPart' => 'Hello',
]);
dump($response);
Do this in php artisan tinker or a one-off command before building abstractions. Confirm: (a) authentication works, (b) the endpoint version the package targets is still live in Mailjet, and (c) the response shape. Because the package predates Mailjet API v3, the endpoint version is the single biggest risk.
Wrap the client behind your own gateway. This package has no interfaces and no maintained test suite, so you want a seam that lets you swap it for the official mailjet/mailjet-apiv3-php SDK later without touching call sites.
namespace App\Services\Mailjet;
class MailjetGateway
{
public function __construct(private object $client) {}
public function sendTransactional(array $payload): array
{
$response = $this->client->post('send', $payload);
// Normalize whatever the package returns into a plain array
return is_string($response)
? json_decode($response, true) ?? []
: (array) $response;
}
}
Bind it as a singleton in a service provider, with configuration in config/services.php:
$this->app->singleton(MailjetGateway::class, fn () => new MailjetGateway(
new \Knp\Mailjet\Client(
config('services.mailjet.key'),
config('services.mailjet.secret')
)
));
Put sends on the queue. Transactional email should never block a request. Create a job that accepts a serializable payload (arrays/DTOs, not the client itself — the client and its cURL handle are not queue-safe):
class SendMailjetMessage implements ShouldQueue
{
use Queueable, InteractsWithQueue;
public int $tries = 3;
public array $backoff = [10, 60, 300];
public function __construct(public array $payload) {}
public function handle(MailjetGateway $gateway): void
{
$result = $gateway->sendTransactional($this->payload);
// inspect $result for per-message errors before assuming success
}
}
Centralize template IDs and sender identities. Mailjet template-based sending (TemplateID + Variables) is much easier to maintain than inline HTML. Keep a constants class or config map so template IDs are not scattered across jobs and controllers.
Normalize the payload shape in one place. Build a small MailjetMessage value object that emits the array the package expects. This keeps Mailjet-specific field names (From, To, TextPart, HTMLPart, TemplateID, Variables) out of your domain code and makes the eventual SDK migration mechanical.
Handle webhooks separately. Mailjet bounce/open/click events arrive as HTTP POSTs. The package is unlikely to provide webhook verification helpers; implement a controller that validates the payload and dispatches Laravel events. Do not rely on the package for this.
Testing. Because the client probably performs cURL calls directly, do not try to mock it. Fake MailjetGateway in feature tests and assert your job/controller called it with the expected payload. Keep a thin integration test (manually run, or gated behind an env flag) that hits Mailjet's API with a test address.
Integration tip for Laravel mail. If all you need is transactional email, Laravel can send through Mailjet over SMTP without this package at all. Reserve the API wrapper for template sends, contact-list management, or campaign operations that SMTP cannot do.
each(), or loose comparisons if it runs at all on modern PHP.Status/Errors, not just the transport status.401 usually means you used the wrong pair.composer dump-autoload -o output, not assumptions about the namespace.429/5xx with exponential backoff. Do not retry blindly on 4xx validation errors.sendTransactional, maybe addContact). When you switch to the official SDK, only the gateway implementation should change.How can I help you explore Laravel packages today?