Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Swiftmailer Sparkpost Bundle Laravel Package

g1ntas/swiftmailer-sparkpost-bundle

A Symfony bundle that integrates SparkPost with Swift Mailer, providing a transport so applications can send email through SparkPost's API using the standard Swift Mailer interface and bundle configuration.

View on GitHub
Deep Wiki
Context7

Getting Started

The short version: you can't install this in a Laravel app, and you shouldn't.

g1ntas/swiftmailer-sparkpost-bundle is a Symfony bundle. It is registered through AppKernel::registerBundles() / bundles.php, ships its wiring as a DependencyInjection\Extension plus Resources/config/services.yml, and its whole job is to swap the transport underneath Symfony's swiftmailer service. Laravel has no bundle kernel, no swiftmailer service, and uses Illuminate\Mail\MailManager instead. There is nothing here for Laravel to boot.

Compounding that: the repo is archived, last released 2017-10-10, has 2 stars and 0 dependents, and is pinned to Swiftmailer, which reached end of life in November 2021. Laravel 9+ replaced Swiftmailer with Symfony Mailer, so even the transport class's interface signatures no longer exist in a modern application.

So the first step for a Laravel developer is: skip the package and use SparkPost's SMTP relay. SparkPost speaks plain SMTP at smtp.sparkpostmail.com:587 (EU: smtp.eu.sparkpostmail.com), username SMTP_Injection, password = your API key. That is a five-minute job with zero dependencies and zero unmaintained code:

// config/mail.php
'mailers' => [
    'sparkpost' => [
        'transport' => 'smtp',
        'host' => env('SPARKPOST_HOST', 'smtp.sparkpostmail.com'),
        'port' => env('SPARKPOST_PORT', 587),
        'encryption' => 'tls',
        'username' => env('SPARKPOST_USERNAME', 'SMTP_Injection'),
        'password' => env('SPARKPOST_API_KEY'),
        'timeout' => null,
    ],
    // ...
],
MAIL_MAILER=sparkpost
SPARKPOST_API_KEY=<your sending key>

First real use case: password resets, receipts, and notification mail through a Mailable — exactly as you would with SES or Postmark. Nothing about your Mail::to(...)->send(new Receipt($order)) code changes. Verify the wiring with a single Mail::raw() to your own address before migrating any real flows.

If you genuinely need the API transport (better throughput control, transmission_id tracking, per-recipient metadata — SMTP gives you none of that cleanly), don't pull the bundle. Read its transport class in src/ as a reference implementation and port the ~100 lines into a Laravel mail transport (see below). Treat the rest of the bundle as documentation, not code.

Implementation Patterns

Pattern 1 — SMTP relay (recommended default)

Configure the mailer as above and keep using Mailables, queues, and Mail::fake() as normal. This is the pattern 95% of Laravel teams should use, because it preserves every Laravel mail feature (attachments, inline images, localization, later(), Mail::assertQueued()) with no custom transport code.

Mail::to($user)->queue(new PasswordReset($token));

Add 'queue' => true on high-volume mailers, or implement ShouldQueue per Mailable, so SparkPost's API latency and 429s never block a request.

Pattern 2 — Porting the transport to a Laravel mail driver

If you need the API, write the transport yourself on top of Symfony Mailer's AbstractTransport. This is the shape the bundle's Swiftmailer class would take if you translated it:

namespace App\Mail\Transport;

use Illuminate\Support\Facades\Http;
use Symfony\Component\Mailer\SentMessage;
use Symfony\Component\Mailer\Transport\AbstractTransport;
use Symfony\Component\Mime\Address;
use Symfony\Component\Mime\MessageConverter;

class SparkPostTransport extends AbstractTransport
{
    public function __construct(
        private string $apiKey,
        private string $endpoint = 'https://api.sparkpost.com/api/v1',
    ) {
        parent::__construct();
    }

    protected function doSend(SentMessage $message): void
    {
        $email = MessageConverter::toEmail($message->getOriginalMessage());
        $from  = $email->getFrom()[0];

        $response = Http::withHeaders(['Authorization' => $this->apiKey]) // NOT "Bearer"
            ->acceptJson()
            ->timeout(15)
            ->post("{$this->endpoint}/transmissions", [
                'recipients' => array_map(
                    fn (Address $a) => ['address' => ['email' => $a->getAddress(), 'name' => $a->getName()]],
                    $email->getTo()
                ),
                'content' => [
                    'from'    => ['email' => $from->getAddress(), 'name' => $from->getName()],
                    'subject' => $email->getSubject(),
                    'html'    => $email->getHtmlBody(),
                    'text'    => $email->getTextBody(),
                ],
                'options' => ['sandbox' => app()->environment('local')],
            ]);

        $response->throw();

        $message->setMessageId($response->json('results.id'));
    }

    public function __toString(): string
    {
        return 'sparkpost';
    }
}

Register it in a service provider:

// app/Providers/AppServiceProvider.php
use Illuminate\Support\Facades\Mail;

public function boot(): void
{
    Mail::extend('sparkpost', fn (array $config) => new SparkPostTransport(
        apiKey: $config['key'],
        endpoint: $config['endpoint'] ?? 'https://api.sparkpost.com/api/v1',
    ));
}
// config/mail.php — 'transport' key is ignored for custom drivers; pass your own keys
'sparkpost' => [
    'transport' => 'sparkpost',
    'key' => env('SPARKPOST_API_KEY'),
    'endpoint' => env('SPARKPOST_ENDPOINT', 'https://api.sparkpost.com/api/v1'),
],

Note setMessageId() — that's your hook for correlating Laravel logs with SparkPost's Events UI and the message-events API. Capture it.

Pattern 3 — Webhook ingestion for delivery events

Neither SMTP nor the bundle gives you bounce/complaint feedback; you build it. Point a SparkPost webhook at a Laravel route and persist events idempotently:

// routes/api.php
Route::post('/webhooks/sparkpost', SparkPostWebhookController::class)
    ->middleware(['auth.basic:sparkpost_webhook']); // or a shared-secret header check

In the controller, verify the shared secret, dispatch a queued job per event, and de-duplicate on SparkPost's event id — retries are guaranteed and will double-send otherwise. Use this to drive suppression lists before you ever need them.

Pattern 4 — Legacy escape hatch (Laravel ≤ 8 only)

On Laravel 5–8, Mail::extend() resolves a Swift_Transport, so the bundle's transport class is conceptually droppable in via Mail::extend('sparkpost', fn() => new SparkPostTransport($key)). This is the only scenario where the bundle's code is even close to relevant — and by 2017-era code standards it will still fight you on PHP 8 typing, Guzzle major versions, and SparkPost API v1 response shapes.

Gotchas and Tips

Framework mismatch is fatal, not cosmetic. Don't try to register the bundle, don't composer require it into a Laravel app and hunt for a service provider — there isn't one. The DependencyInjection/Configuration.php keys (sparkpost.api_key, etc.) are Symfony tree-builder config and are never read by config/mail.php.

Swiftmailer is gone, and Laravel moved on without it. If your app is Laravel 9+, any code you find in the bundle's send() method maps to Swift_Mime_SimpleMessage; Laravel now hands you Symfony\Component\Mime\Email via SentMessage::getOriginalMessage(). getSwiftMessage() doesn't exist anymore. If you're on Laravel ≤ 8, the reverse applies.

Auth header, not Bearer. SparkPost expects Authorization: <raw api key>; Http::withToken() sends Bearer <key> and will 401. Use withHeaders(), as above.

Archived + 0 dependents + 2 stars = zero bug surface. There is no one to hit the edge cases before you. In particular: no EU endpoint handling, no API v2/v1 deprecation guard, no PHP 8 support, no TLS 1.2 enforcement, and no known patches for the 2017 dependency tree. Treat any code copied from it as untrusted and re-review it.

Sending domain and DKIM first, code second. Most "SparkPost doesn't deliver" tickets are unverified sending domains or a from address that doesn't match the configured domain. Do this before writing a transport — otherwise you'll debug the wrong layer. Set up bounce domains too, or you'll silently drop bounces.

Sandbox mode is an API-only feature. 'options' => ['sandbox' => true] works on /transmissions; the SMTP relay has no equivalent. On SMTP you test with a sandbox sending domain or Mailpit locally.

Debug in this order: MAIL_MAILER=log to confirm Laravel rendered the message → Http::fake()/Mail::fake() to confirm your transport is called → SparkPost Events UI filtered by transmission_id → the message-events API for per-recipient detail. Set MAIL_LOG_CHANNEL so swallowed transport exceptions don't disappear into laravel.log.

Mail::fake() doesn't exercise your transport. It short-circuits MailManager entirely. Your custom transport needs its own test with Http::fake() asserting the request body and the Authorization header — that's the only place a typo in the endpoint or payload shape will surface.

Rate limits are per-account and per-endpoint. Queue everything and wrap doSend() with retry/backoff on 429 (->retry(3, 500) on the Http call, or let the queue's $backoff handle it). Don't retry 4xx other than 429 — a malformed recipient will never succeed.

Extension points worth knowing instead of the bundle: Mail::extend() for the driver, Mailable::withSymfonyMessage(fn (Email $e) => ...) on Laravel 9+ (or ->getSwiftMessage() on legacy) to attach SparkPost metadata headers, Mailable::headers() for List-Unsubscribe, and per-mailer 'transport' overrides so transactional and marketing traffic can be split across mailers.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
ippanelcom/laravel-sdk
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus