Skip to main content

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

Package on Packagist: jetemail/jetemail-laravel. Source on GitHub: jetemail/jetemail-laravel. The service provider (JetEmail\Laravel\JetEmailServiceProvider) and the JetEmail facade alias are auto-discovered by Laravel.

Configuration

Add your transactional API key to your .env file:
Optionally publish the config file to config/jetemail.php:
All settings and their environment variables: 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 your config/mail.php:
Set it as your default mailer in .env:
Then use Laravel’s standard Mail API:
This works with all Laravel Mailables and Notifications out of the box. The transport maps from/to/cc/bcc/reply-to, the HTML and text bodies, custom headers and attachments onto a JetEmail send, and adds the returned message ID to the sent message as an X-JetEmail-Id header. API failures surface as a Symfony TransportException.

Direct API Usage

Resolving the client

The JetEmail\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

Use a 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 with JetEmail\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 of SendEmailOptions. Returns summary (total, successful, failed) and results per message (success with id, or error with error).

Without Laravel

The JetEmail 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:
The webhook endpoint is automatically registered at 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 your EventServiceProvider or using Event::listen():
In your listener:
Every event class has a single 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 the JetEmail\Laravel\Events\Outbound namespace.

Signature verification

Webhook signatures are automatically verified when JETEMAIL_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-Signature header (sha256=<hex digest> of the raw request body)
  • Timestamp freshness via X-Webhook-Timestamp (default: 5-minute tolerance)
Requests that fail either check are rejected with a 403 response. You can adjust the tolerance (in seconds; 0 disables the timestamp check):

Error Handling

API errors throw JetEmail\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.