Laravel SDK
The jetemail/jetemail-laravel package is the official Laravel SDK for JetEmail transactional email (MIT license, PHP 8.1+, Laravel 10, 11 or 12, Guzzle 7). Create a transactional API key in the dashboard: Outbound → Keys → Add API key. Use that key with the SDK.Not using Laravel? Use the framework-agnostic PHP SDK instead.
Installation
JetEmail\Laravel\JetEmailServiceProvider) and the JetEmail facade alias are auto-discovered by Laravel.
Configuration
Add your transactional API key to your.env file:
config/jetemail.php:
If
jetemail.api_key is empty the SDK falls back to services.jetemail.key in config/services.php. If neither is set, resolving the client throws JetEmail\Laravel\Exceptions\ApiKeyIsMissing.
Laravel Mail Integration
Use JetEmail as a Laravel mail driver. Add the mailer to yourconfig/mail.php:
.env:
X-JetEmail-Id header. API failures surface as a Symfony TransportException.
Direct API Usage
Resolving the client
TheJetEmail\Laravel\JetEmail client is bound in the container as a singleton (also aliased as jetemail) and exposes two services:
email and batch are instance properties, not methods, so they cannot be reached through the facade’s static syntax (JetEmail::email is parsed by PHP as a class constant and throws Undefined constant). If you prefer the facade, unwrap it first: \JetEmail\Laravel\Facades\JetEmail::getFacadeRoot()->email->send(...).Send a single email
from address on a verified domain (see Getting started).
SendEmailOptions accepts the following named constructor arguments:
Responses are plain PHP arrays decoded from the API response; a single send returns
['id' => string, 'response' => string].
Send with plain text
Multiple recipients, CC, BCC, Reply-To
Attachments
Build attachments withJetEmail\Laravel\Data\Attachment. The helpers base64-encode the content for you; fromPath() takes an optional second argument to override the filename (defaults to the file’s basename).
Custom headers
Batch send (up to 100 emails)
Pass an array ofSendEmailOptions. Returns summary (total, successful, failed) and results per message (success with id, or error with error).
Without Laravel
TheJetEmail client class only uses Guzzle at runtime, so it can be constructed directly without the container (the package still pulls in its illuminate/* dependencies when installed):
Webhooks
JetEmail can send webhook events to your application for email delivery events.Setup
Add your webhook secret to.env:
POST /jetemail/webhook (route name jetemail.webhook). Point your JetEmail dashboard webhook URL to https://yourdomain.com/jetemail/webhook.
Configuration
You can customise the webhook route prefix and domain:Listening for events
Listen for webhook events in yourEventServiceProvider or using Event::listen():
public readonly array $payload property containing the decoded webhook body. Events with a type the SDK doesn’t recognise are acknowledged with 200 Webhook received and no event is dispatched.
Available events
All classes live under theJetEmail\Laravel\Events\Outbound namespace.
Signature verification
Webhook signatures are automatically verified whenJETEMAIL_WEBHOOK_SECRET is set (the JetEmail\Laravel\Http\Middleware\VerifyWebhookSignature middleware is attached to the route). The middleware validates:
- HMAC-SHA256 signature via the
X-Webhook-Signatureheader (sha256=<hex digest>of the raw request body) - Timestamp freshness via
X-Webhook-Timestamp(default: 5-minute tolerance)
0 disables the timestamp check):
Error Handling
API errors throwJetEmail\Laravel\Exceptions\JetEmailException. Requests that fail client-side validation (missing from, to or subject, neither html nor text, an empty batch or more than 100 emails in a batch) throw a standard InvalidArgumentException before any request is made.
For the full source and additional examples, see the GitHub repository. REST details: API reference.