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

Sparkpost Bundle Laravel Package

tlamedia/sparkpost-bundle

Symfony bundle that wraps the SparkPost email API, providing configuration, service definitions, and a simple way to send transactional messages from your application. It streamlines setup so you can focus on mail features instead of API plumbing, whether sending from controllers, commands, or servi...

View on GitHub
Deep Wiki
Context7

Getting Started

Read the framework mismatch first. Despite being evaluated from a Laravel seat, tlamedia/sparkpost-bundle is a Symfony bundle (the Bundle suffix and Tlamedia's DI extension convention confirm it). It has no Laravel service provider, no facade, and no config/mail.php integration. Before installing anything, decide which of these is true for you:

  • You're on Symfony → install and configure it normally.
  • You're on Laravel → you are most likely going to consume the underlying sparkpost/sparkpost SDK, or reuse the bundle's Symfony Mailer transport class through Laravel's Mail::extend() bridge (Laravel 9+ runs on Symfony Mailer, so the transport is compatible in principle).

Minimal Symfony path:

composer require tlamedia/sparkpost-bundle
// config/bundles.php
Tlamedia\SparkPostBundle\SparkPostBundle::class => ['all' => true],
SPARKPOST_API_KEY=your-key
# config/packages/mailer.yaml — point the mailer at the transport the bundle registers
framework:
    mailer:
        dsn: '%env(MAILER_DSN)%'
# DSN scheme provided by the bundle's transport factory
MAILER_DSN=sparkpost+api://%env(SPARKPOST_API_KEY)%@default

Where to look first (in order):

  1. README.md — the only reliable source for the exact DSN scheme, config key namespace (tlamedia_sparkpost or similar), and whether an EU/US endpoint host is configurable.
  2. DependencyInjection/*Extension.php — tells you the real service IDs and parameters you can override.
  3. Transport/* — the transport and factory classes; these are what you'll bridge or decorate.
  4. composer.json — check the symfony/mailer and PHP constraints. A 2023-02-07 release may not declare support for Symfony 7.

First use case: send one transactional email through Symfony Mailer with the SparkPost transport, confirm it lands in SparkPost's UI/events, then confirm a template + substitution-data path works end-to-end. That second step is where the bundle either earns its place or forces you onto the SDK.

Implementation Patterns

1. Let Symfony Mailer own sending; let SparkPost own delivery. Use the standard MailerInterface/Email API and treat SparkPost as an opaque transport:

use Symfony\Component\Mime\Email;

$email = (new Email())
    ->from('[email protected]')
    ->to($user->email)
    ->subject('Welcome')
    ->html($twig->render('email/welcome.html.twig', $data));

$mailer->send($email);

2. Multi-transport routing. Symfony's framework.mailer allows multiple transports and header/recipient-based routing. Use a sparkpost transport for bulk/marketing-ish mail and a smtp transport for critical transactional mail, then route by X-Transport header:

framework:
    mailer:
        transports:
            sparkpost: '%env(SPARKPOST_DSN)%'
            smtp: '%env(SMTP_DSN)%'
$email->getHeaders()->addTextHeader('X-Transport', 'sparkpost');

This is the pattern that best uses the bundle — it makes SparkPost a swappable transport rather than a hard dependency.

3. Laravel bridge via Mail::extend(). If you're committed to Laravel and want the bundle's transport, register a custom mailer driver. Verify the constructor signature against the actual class — treat this as a skeleton:

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

public function boot(): void
{
    Mail::extend('sparkpost', function (array $config) {
        return new \Tlamedia\SparkPostBundle\Transport\SparkPostTransport(
            $config['key'],
            // event dispatcher, endpoint host, etc. — check the real signature
        );
    });
}
// config/mail.php
'mailers' => [
    'sparkpost' => [
        'transport' => 'sparkpost',
        'key' => env('SPARKPOST_API_KEY'),
    ],
],

For most Laravel teams the lower-risk path is to skip the bridge and either (a) use sparkpost/sparkpost directly in a small SparkPostMailer service, or (b) use Symfony Mailer's transport in a thin wrapper. The bundle itself adds ~nothing for Laravel beyond re-exposing the transport.

4. SparkPost-specific features via headers. Symfony's Email doesn't model substitution data, stored templates, tags, or metadata. The common pattern is to attach them as headers that the transport (or SparkPost's REST layer) reads, e.g. X-SparkPost-Campaign, X-SparkPost-Template, or metadata headers. Confirm in the transport source which headers it actually maps — if it maps none, use the SDK for template sends and keep the bundle for plain mail.

5. Template sending. For stored templates, the most robust pattern is to keep templating in SparkPost and send only template_id + substitution data through the raw API via the SDK, because Symfony's Email/Mime model doesn't express either concept natively. Use the bundle for plain HTML/plaintext mail, the SDK for template mail. Don't try to force one tool to do both.

6. Testing. Never hit SparkPost in tests:

# config/packages/test/mailer.yaml
framework:
    mailer:
        dsn: 'null://null'

Then assert on the MessageEvent via a listener, or use symfony/mailer's MessageLoggerListener and inspect getEvents(). For Laravel, Mail::fake() works normally regardless of the underlying transport.

7. Observability. SparkPost's value is its events/webhooks API, and this bundle almost certainly does not provide webhook handling (no controllers, no event subscribers are typical for a package this size). Plan to add a small controller that verifies the webhook signature and persists delivery/bounce/open events yourself.

Gotchas and Tips

Framework fit. This is the single biggest gotcha: Laravel developers will find no SparkPostServiceProvider, no publishable config, no facade. Every integration step is manual. Budget for that before you adopt it.

Adoption and maintenance risk. 3 stars, 0 dependents, a 0.015 score, and a last release in February 2023 is a red flag. Treat it as "a thin wrapper you might fork" rather than a dependency you can lean on. Practically:

  • Pin it exactly ("tlamedia/sparkpost-bundle": "x.y.z") and commit composer.lock.
  • Check composer.json constraints against your PHP and symfony/mailer versions. Symfony 7 / Laravel 11 may be untested.
  • Read Transport/* in full before relying on it — it is small enough to audit in an afternoon, which is also its main advantage.

DSN encoding. API keys are placed in the DSN userinfo position. Keys with @, :, /, or + must be URL-encoded or you'll get confusing TransportExceptions. Prefer building the DSN from an env var that you control rather than interpolating the raw key.

SparkPost region. SparkPost has US (api.sparkpost.com) and EU (api.eu.sparkpost.com) endpoints. If your account is EU and the bundle hardcodes the US host or doesn't expose a configurable host parameter, sends will fail with auth/permission errors that look like bad keys. Check DependencyInjection/*Extension.php for a host/endpoint parameter; if absent, that's a fork-level fix.

Error surfacing. Symfony transports wrap failures in Symfony\Component\Mailer\Exception\TransportExceptionInterface. SparkPost returns JSON error bodies with useful errors[].message / code fields, but the wrapped exception often loses that detail. Catch the transport exception, and if debugging, bypass the bundle and call the SDK directly to see the raw response. Log the response body at debug level in a decorator on the transport if you need ongoing visibility.

Transport exceptions are not all equal. SparkPost distinguishes 4xx (bad request, invalid recipient, rate limit 429) from 5xx (retryable). Symfony Mailer will not retry for you. If you need retry/backoff on 429s, wrap MailerInterface in a decorator or push those sends through a queue (Symfony Messenger or Laravel queues) rather than sending inline.

Extension points are your friend.

  • Decorate the transport factory to change endpoint hosts or inject a custom HTTP client.
  • Decorate the transport to add logging/metrics without touching vendor code.
  • Listen to Symfony\Component\Mailer\Event\MessageEvent to stamp headers, enforce from-addresses, or block sends to non-production recipients in staging.

No templating, no webhooks, no suppression management. The bundle is a mail transport, not a SparkPost client. Anything beyond "put this MIME message on the wire" — templates, substitution data, tags, metadata, inbound/webhook events, suppression lists, sending domains — belongs to the sparkpost/sparkpost SDK or raw REST calls. Design your integration so those two concerns are separated from the start, or you will fight the abstraction.

Debugging checklist, in order: (1) swap to null:// to confirm the app path is fine; (2) hit SparkPost's API with curl using the same key to confirm credentials/region; (3) enable Symfony's mailer profiler and inspect the raw message; (4) only then suspect the bundle. Because the transport is thin, most failures are credentials, DSN encoding, or region — not the bundle itself.

When to fork instead of depend. Given the maintenance profile, if you need EU endpoints, template headers, or Symfony 7 support, vendor the two or three transport files into your app (or a small internal package) and drop the dependency. The bundle is small enough that the fork cost is low and the supply-chain risk disappears. For a Laravel team, this is usually the better call than maintaining a Mail::extend() bridge to a Symfony-only package.

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.
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package
kda/filament-dynamic-navigation
bypersoft/signbox
pairus/product-data
fayne/laravel-filament-cms-core