PHPackages                             brunocfalcao/laravel-zepto-mail-api-driver - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Mail &amp; Notifications](/categories/mail)
4. /
5. brunocfalcao/laravel-zepto-mail-api-driver

ActiveLibrary[Mail &amp; Notifications](/categories/mail)

brunocfalcao/laravel-zepto-mail-api-driver
==========================================

Zeptomail api mail driver for Laravel

v1.1.0(1mo ago)12.6k2MITPHPPHP ^8.1

Since Nov 2Pushed 1mo ago1 watchersCompare

[ Source](https://github.com/brunocfalcao/laravel-zepto-mail-api-driver)[ Packagist](https://packagist.org/packages/brunocfalcao/laravel-zepto-mail-api-driver)[ Docs](https://github.com/brunocfalcao/brunocfalcao/laravel-zepto-mail-api-driver)[ RSS](/packages/brunocfalcao-laravel-zepto-mail-api-driver/feed)WikiDiscussions master Synced 3d ago

READMEChangelogDependencies (1)Versions (3)Used By (0)

Laravel ZeptoMail API Driver
============================

[](#laravel-zeptomail-api-driver)

[![Latest Version on Packagist](https://camo.githubusercontent.com/b0381adf41441650d0ae320412d3d3081e09c2f9d3781d7f9928bcd62fdbaaa3/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6272756e6f6366616c63616f2f6c61726176656c2d7a6570746f6d61696c2d6472697665722e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/brunocfalcao/laravel-zeptomail-driver)[![Total Downloads](https://camo.githubusercontent.com/1289ea1b4b1aa57fdbfd515945f2cf26e8096bed70aedbafbcfa4b3c9020c2ac/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6272756e6f6366616c63616f2f6c61726176656c2d7a6570746f6d61696c2d6472697665722e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/brunocfalcao/laravel-zeptomail-driver)

A lightweight **Symfony Mailer transport** for Laravel that delivers mail via **ZeptoMail’s HTTP API** (no SMTP). It plugs into Laravel’s `mailers` and supports **CC/BCC/Reply-To**, **attachments &amp; inline (CID) images**, **single &amp; batch sending**, **template sending (single &amp; batch)**, **custom MIME headers**, **open/click tracking flags**, and a **client reference**. Under the hood it uses Laravel’s `Http` client, so you can **`Http::fake()`** in tests.

---

Requirements
------------

[](#requirements)

- PHP 8.1+
- Laravel 9.x / 10.x / 11.x (Symfony Mailer)
- Outbound HTTPS and TLS 1.2 available
- A ZeptoMail account &amp; API key (use the correct **region endpoint**, e.g. `.com` or `.eu`)

---

Installation
------------

[](#installation)

Install via Composer:

```
composer require brunocfalcao/laravel-zeptomail-driver
```

If you don’t use package discovery, register the provider manually:

```
// config/app.php
'providers' => [
    // ...
    Brunocfalcao\ZeptoMailApiDriver\ZeptoMailApiDriverServiceProvider::class,
],
```

---

Configuration
-------------

[](#configuration)

### 1) Environment

[](#1-environment)

```
# .env
MAIL_MAILER=zeptomail
MAIL_FROM_ADDRESS=hello@yourdomain.com
MAIL_FROM_NAME="Your App"

# Driver secret
ZEPTOMAIL_MAIL_KEY=your-zeptomail-api-key

# Region endpoint (pick the one for your account):
ZEPTO_MAIL_ENDPOINT=https://api.zeptomail.com
# ZEPTO_MAIL_ENDPOINT=https://api.zeptomail.eu

# Optional tuning
ZEPTO_MAIL_TIMEOUT=30
ZEPTO_MAIL_RETRIES=2
ZEPTO_MAIL_RETRY_MS=200

# Optional defaults
ZEPTO_MAIL_TEMPLATE_KEY=           # or ZEPTO_MAIL_TEMPLATE_ALIAS=
ZEPTO_MAIL_BOUNCE_ADDRESS=         # templates API only
ZEPTO_MAIL_TRACK_OPENS=false
ZEPTO_MAIL_TRACK_CLICKS=false
ZEPTO_MAIL_CLIENT_REFERENCE=
ZEPTO_MAIL_FORCE_BATCH=false
```

> The service provider reads `config('services.zeptomail.mail_key')` and falls back to `env('ZEPTOMAIL_MAIL_KEY')`.

### 2) `config/services.php`

[](#2-configservicesphp)

```
// config/services.php (excerpt)
return [
    // ...
    'zeptomail' => [
        // Primary: configure here. Fallback: env('ZEPTOMAIL_MAIL_KEY')
        'mail_key'        => env('ZEPTOMAIL_MAIL_KEY'),

        // Use .eu if your account lives in the EU region
        'endpoint'        => env('ZEPTO_MAIL_ENDPOINT', 'https://api.zeptomail.com'),

        // HTTP client tuning
        'timeout'         => env('ZEPTO_MAIL_TIMEOUT', 30),
        'retries'         => env('ZEPTO_MAIL_RETRIES', 2),
        'retry_sleep_ms'  => env('ZEPTO_MAIL_RETRY_MS', 200),

        // Optional defaults for convenience
        'template_key'    => env('ZEPTO_MAIL_TEMPLATE_KEY'),
        'template_alias'  => env('ZEPTO_MAIL_TEMPLATE_ALIAS'),
        'bounce_address'  => env('ZEPTO_MAIL_BOUNCE_ADDRESS'),
        'track_opens'     => env('ZEPTO_MAIL_TRACK_OPENS', false),
        'track_clicks'    => env('ZEPTO_MAIL_TRACK_CLICKS', false),
        'client_reference'=> env('ZEPTO_MAIL_CLIENT_REFERENCE'),
        'force_batch'     => env('ZEPTO_MAIL_FORCE_BATCH', false),
    ],
];
```

### 3) `config/mail.php`

[](#3-configmailphp)

```
// config/mail.php (excerpt)
return [
    'default' => env('MAIL_MAILER', 'smtp'),

    'mailers' => [
        'smtp' => [
            'transport' => 'smtp',
            // ...
        ],

        'zeptomail' => [
            'transport' => 'zeptomail', // registered by the ServiceProvider
        ],
    ],

    'from' => [
        'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'),
        'name'    => env('MAIL_FROM_NAME', 'Example'),
    ],
];
```

---

Usage
-----

[](#usage)

You can use this transport like any other Laravel mailer.

### Single email (default)

[](#single-email-default)

```
use Illuminate\Support\Facades\Mail;
use App\Mail\InvoiceReady;

Mail::to('a@example.com')->send(new InvoiceReady());
// -> POST /v1.1/email
```

### Select the mailer per send

[](#select-the-mailer-per-send)

```
Mail::mailer('zeptomail')->to('a@example.com')->send(new InvoiceReady());
```

### CC / BCC / Reply-To

[](#cc--bcc--reply-to)

```
Mail::mailer('zeptomail')->send(
    (new App\Mail\SimpleMessage)
        ->to('to@example.com')
        ->cc(['cc1@example.com', 'cc2@example.com'])
        ->bcc('audit@example.com')
        ->replyTo('reply@example.com')
);
```

### Attachments &amp; Inline (CID) images

[](#attachments--inline-cid-images)

```
// App\Mail\ReportMail
public function build()
{
    $cid = $this->embed(public_path('img/logo.png')); //
    return $this->subject('Monthly Report')
        ->view('emails.report', compact('cid'))
        ->attach(storage_path('app/reports/monthly.pdf')); // regular attachment
}
```

The driver maps attachments to `attachments[]` and CID images to `inline_images[]` with `cid` set accordingly.

### Custom MIME headers, tracking, and client reference

[](#custom-mime-headers-tracking-and-client-reference)

```
public function build()
{
    return $this->subject('Security Alert')
        ->view('emails.security')
        ->withSymfonyMessage(function (Symfony\Component\Mime\Email $email) {
            // Custom headers → go under Zepto's mime_headers
            $email->getHeaders()->addTextHeader('X-Custom-Header', 'abc-123');

            // Tracking flags
            $email->getHeaders()->addTextHeader('X-Zepto-Track-Opens', 'true');
            $email->getHeaders()->addTextHeader('X-Zepto-Track-Clicks', 'false');

            // Optional client reference
            $email->getHeaders()->addTextHeader('X-Zepto-Client-Reference', 'user#42-event#login');
        });
}
```

---

Batch sending (per-recipient personalization &amp; hidden recipients)
---------------------------------------------------------------------

[](#batch-sending-per-recipient-personalization--hidden-recipients)

Use **batch** when sending to a collection of recipients. Recipients are **not visible to each other**. You can also provide **per-recipient `merge_info`**.

### Batch (non-template)

[](#batch-non-template)

```
use Illuminate\Support\Facades\Mail;

$recipients = ['alice@example.com', 'bob@example.com', 'carol@example.com'];

$perRecipient = [
    'alice@example.com' => ['name' => 'Alice', 'tier' => 'gold'],
    'bob@example.com'   => ['name' => 'Bob',   'tier' => 'silver'],
    // carol has no specific merge vars
];

Mail::to($recipients)->send(
    (new App\Mail\PromoMail)
        ->withSymfonyMessage(function (Symfony\Component\Mime\Email $email) use ($perRecipient) {
            // Force Zepto batch endpoint
            $email->getHeaders()->addTextHeader('X-Zepto-Batch', 'true');
            // Provide per-recipient merge vars
            $email->getHeaders()->addTextHeader('X-Zepto-PerRecipient-MergeInfo', json_encode($perRecipient));
        })
);
// -> POST /v1.1/email/batch
```

> You can globally enforce batch via `services.zeptomail.force_batch=true` if you prefer.

---

Template sending
----------------

[](#template-sending)

Send using a **template key or alias** (single or batch). Provide **global `merge_info`**, plus **per-recipient `merge_info`** in batch.

### Single template email

[](#single-template-email)

```
use Illuminate\Support\Facades\Mail;

Mail::to('jane@example.com')->send(
    (new App\Mail\Templated)
        ->withSymfonyMessage(function (Symfony\Component\Mime\Email $email) {
            // Key or alias (the driver handles either)
            $email->getHeaders()->addTextHeader('X-Zepto-Template', 'my-template-alias'); // or 'ea36f19a...'

            // Global merge vars for this email
            $email->getHeaders()->addTextHeader('X-Zepto-MergeInfo', json_encode([
                'name'       => 'Jane',
                'reset_link' => 'https://example.com/reset/xyz',
            ]));

            // Optional bounce address (templates API)
            $email->getHeaders()->addTextHeader('X-Zepto-Bounce-Address', 'bounce@bounce.example.com');
        })
);
// -> POST /v1.1/email/template
```

### Batch template email

[](#batch-template-email)

```
use Illuminate\Support\Facades\Mail;

$recipients = ['a@example.com', 'b@example.com'];

$perRecipient = [
    'a@example.com' => ['name' => 'Alice', 'coupon' => 'ALC-10'],
    'b@example.com' => ['name' => 'Bob',   'coupon' => 'BOB-15'],
];

Mail::to($recipients)->send(
    (new App\Mail\Templated)
        ->withSymfonyMessage(function (Symfony\Component\Mime\Email $email) use ($perRecipient) {
            $email->getHeaders()->addTextHeader('X-Zepto-Template', 'my-template-alias');
            $email->getHeaders()->addTextHeader('X-Zepto-Batch', 'true');
            $email->getHeaders()->addTextHeader('X-Zepto-PerRecipient-MergeInfo', json_encode($perRecipient));

            // Optional global merge vars across all recipients
            $email->getHeaders()->addTextHeader('X-Zepto-MergeInfo', json_encode([
                'product' => 'Pro Plan',
            ]));
        })
);
// -> POST /v1.1/email/template/batch
```

---

Testing with `Http::fake()`
---------------------------

[](#testing-with-httpfake)

Because this driver uses Laravel’s HTTP client, you can fake the API easily:

```
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Mail;
use App\Mail\InvoiceReady;

test('sends via zeptomail', function () {
    Http::fake([
        'https://api.zeptomail.com/*' => Http::response(['data' => [['message' => 'Email request received']]], 200),
        // or match your EU endpoint:
        // 'https://api.zeptomail.eu/*' => Http::response([...], 200),
    ]);

    Mail::to('test@example.com')->send(new InvoiceReady());

    Http::assertSent(function ($request) {
        return str_ends_with($request->url(), '/v1.1/email')
            && $request->method() === 'POST'
            && $request->json('subject') === 'Your invoice';
    });
});
```

---

Queues
------

[](#queues)

Mailables work seamlessly on queues. Ensure your workers have the same `.env` values and outbound HTTPS access. If using Horizon, watch memory/timeouts on bursts of batch sends.

---

Troubleshooting
---------------

[](#troubleshooting)

- **401 / auth errors** → Verify the key and that you’re using the correct regional endpoint (`.com` vs `.eu`).
- **“error” in response JSON** → The driver throws if the Zepto response includes an `error` object; check domain/sender verification and payload shape.
- **Inline images not showing** → Ensure you embed and reference the returned `cid` (``).
- **Recipients visibility** → Use **batch** endpoints to hide recipients; single-email endpoint can expose them.
- **Rate limits / large sends** → Batch endpoints support a large number of recipients per request (subject to your Zepto plan). Split very large lists and back off with retries if needed.

---

How it works
------------

[](#how-it-works)

- `ZeptoMailApiDriverServiceProvider` registers the `zeptomail` transport.
- `ZeptoMailTransport` converts the Symfony `Email` into Zepto payloads and calls the correct endpoint based on headers/config:
    - `POST /v1.1/email` (single)
    - `POST /v1.1/email/batch` (batch)
    - `POST /v1.1/email/template` (template single)
    - `POST /v1.1/email/template/batch` (template batch)

It also maps: from/to/cc/bcc/reply-to, subject, html/text, attachments, inline images, `mime_headers`, tracking flags, `client_reference`, and (for templates) `merge_info` &amp; optional `bounce_address`.

---

Changelog
---------

[](#changelog)

See [CHANGELOG](CHANGELOG.md).

---

Contributing
------------

[](#contributing)

PRs are welcome. If you add fields, please link the specific Zepto docs section in your PR description and include tests with `Http::fake()`.

---

Security
--------

[](#security)

Keep secrets in `.env`. Rotate API keys periodically. Consider setting a dedicated **bounce address** when using template APIs.

---

License
-------

[](#license)

The MIT License (MIT). See [LICENSE](LICENSE.md) for details.

###  Health Score

45

—

FairBetter than 91% of packages

Maintenance89

Actively maintained with recent releases

Popularity25

Limited adoption so far

Community11

Small or concentrated contributor base

Maturity45

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 68.8% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~189 days

Total

2

Last Release

54d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/26642608?v=4)[Bruno Falcão](/maintainers/brunofalcao)[@brunofalcao](https://github.com/brunofalcao)

---

Top Contributors

[![martingalian](https://avatars.githubusercontent.com/u/237761498?v=4)](https://github.com/martingalian "martingalian (11 commits)")[![brunocfalcao](https://avatars.githubusercontent.com/u/34269950?v=4)](https://github.com/brunocfalcao "brunocfalcao (5 commits)")

---

Tags

brunocfalcao

### Embed Badge

![Health badge](/badges/brunocfalcao-laravel-zepto-mail-api-driver/health.svg)

```
[![Health](https://phpackages.com/badges/brunocfalcao-laravel-zepto-mail-api-driver/health.svg)](https://phpackages.com/packages/brunocfalcao-laravel-zepto-mail-api-driver)
```

###  Alternatives

[propaganistas/laravel-disposable-email

Disposable email validator

6023.0M7](/packages/propaganistas-laravel-disposable-email)[spatie/laravel-pdf

Create PDFs in Laravel apps

1.0k4.8M47](/packages/spatie-laravel-pdf)[psalm/plugin-laravel

Psalm plugin for Laravel

3355.3M346](/packages/psalm-plugin-laravel)[illuminate/mail

The Illuminate Mail package.

5910.6M502](/packages/illuminate-mail)[illuminate/notifications

The Illuminate Notifications package.

513.1M1.1k](/packages/illuminate-notifications)[moonshine/moonshine

Laravel administration panel

1.3k253.1k81](/packages/moonshine-moonshine)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
