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

Mandrill Bundle Laravel Package

nedwave/mandrill-bundle

nedwave/mandrill-bundle is a Symfony bundle for integrating Mandrill transactional email into PHP applications. It provides service configuration and API wrappers to send messages, manage templates, and handle Mandrill delivery from Symfony.

View on GitHub
Deep Wiki
Context7

Getting Started

Read this first: nedwave/mandrill-bundle is a Symfony bundle, not a Laravel package. It has no service provider, no config publishing, no facade. Treat it as a thin DI wrapper around the mandrill/mandrill SDK — useful on Symfony 2/3, mostly useful as a reference implementation on Laravel.

Where to look before installing anything:

  1. composer.json — check the Symfony version constraint and PHP constraint. If it pins Symfony ^2.8 or ~3.0 and PHP ~5.5, it will not install cleanly alongside Laravel 10/11 and PHP 8.2.
  2. DependencyInjection/NedwaveMandrillExtension.php — this is where the api_key config is mapped into the service definition. That's the only real logic in the bundle.
  3. Resources/config/services.xml (or .yml) — confirm the service ID and whether an alias (mandrill, nedwave.mandrill) is registered.
  4. The single wrapper class — usually a Mandrill subclass or a __call passthrough. That tells you whether you get the raw SDK or a narrowed API.

Minimal Symfony setup (the intended use case):

# config.yml
nedwave_mandrill:
    api_key: %mandrill_api_key%
// AppKernel.php
new Nedwave\MandrillBundle\NedwaveMandrillBundle(),
$mandrill = $container->get('nedwave_mandrill'); // confirm ID in services.xml
$mandrill->messages->sendTemplate([
    'template_name'  => 'welcome-email',
    'template_content' => [],
    'message' => [
        'to'        => [['email' => $user->email, 'name' => $user->name]],
        'from_email'=> '[email protected]',
        'subject'   => 'Welcome',
        'global_merge_vars' => [['name' => 'FIRST_NAME', 'content' => $user->first_name]],
    ],
]);

Laravel translation: skip the bundle, composer require mandrill/mandrill, and register the SDK in a small service provider. First use case is identical — send a template. The bundle's only value is its DI wiring; you don't need it.

Implementation Patterns

Constructor injection, not container pulls. The bundle exposes the client as a service; inject it so you can swap it in tests:

public function __construct(private \Mandrill $mandrill) {}

Template-first sending. Store all copy in Mandrill's template editor and only pass merge vars from code. This is the pattern that survives marketing changing subject lines without a deploy. Use messages->sendTemplate() (or send with template_name) rather than sendRaw for anything user-facing.

Merge var strategy. Use global_merge_vars for values shared across all recipients in a call, and per-message merge_vars for recipient-specific fields. If you're looping anyway, just use merge_vars.

Batch sends. messages->send() accepts an array of message objects (up to 1000 per call, with subaccount/tag/async mixed) and returns a list of per-message results. This is the idiomatic way to do bulk mail — one HTTP call, not N calls:

$results = $mandrill->messages->send($messages);
foreach ($results as $i => $r) {
    if ($r['status'] !== 'sent' && $r['status'] !== 'queued') {
        // log reject_reason for $messages[$i]
    }
}

Async + webhooks. For non-critical mail, send with 'async' => true and handle outcomes via Mandrill webhooks (send, open, click, hard_bounce, soft_bounce, spam, unsub). Register a single endpoint and dispatch on $event['event']. Always verify X-Mandrill-Signature:

$signed = $webhookUrl;                     // exact URL you registered
ksort($_POST);
foreach ($_POST as $k => $v) { $signed .= $k . $v; }
$expected = base64_encode(hash_hmac('sha1', $signed, $webhookKey, true));
// compare with hash_equals()

Note the bundle does not include webhook receiving — that's yours.

Reputation isolation. Use subaccount per tenant/product and tags per campaign. This is the Mandrill feature people discover too late; retrofitting is painful because history isn't backfillable.

Attachments and headers. Mandrill expects base64 content and a MIME type. Total attachment size is capped (~25 MB). Custom headers go in message.headers — use them for Reply-To, X-Entity-Ref-ID, or list-unsubscribe if not handled by the template.

Test strategy. Do not mock the Mandrill class deeply — it uses magic __get for sub-objects. Prefer an interface you own (Mailer) implemented by MandrillMailer, and fake that. Alternatively set Mandrill's account-level test mode toggle and assert on your own mandrill_events webhook receiving the test payload rather than real delivery.

Gotchas and Tips

  • This is not a Laravel package. There is no MandrillServiceProvider, no config/mandrill.php, no facade. Any tutorial implying otherwise is wrong. On Laravel, use the SDK directly or the official mailchimp/transactional client.
  • Version skew. The bundle almost certainly pins Symfony 2/3 and PHP 5.5–7.x. On modern PHP/Laravel, Composer will refuse or you'll fight constraint conflicts. Check before you require.
  • The SDK underneath is stale. mandrill/mandrill is the old SDK; Mailchimp renamed the product to Mailchimp Transactional and its official client is distributed via GitHub (VCS repository, not Packagist). Pin a commit if you go that route.
  • messages->send() does not throw on failure. It returns [['status' => 'rejected', 'reject_reason' => 'hard-bounce', ...]]. Wrap every call and inspect statuses; do not rely on try/catch for delivery problems.
  • send vs sendTemplate vs sendRaw. send with template_name is the flexible path; sendTemplate requires template_content even if empty; sendRaw skips templates entirely and is only useful for pre-rendered MIME. Don't mix.
  • API key in config. The bundle reads a scalar config value. On older Symfony there's no %env()% interpolation inside bundle config — keep parameters.yml out of VCS and inject via environment at the parameters level, not the bundle level.
  • Base URL. Everything targets https://mandrillapp.com/api/1.0/. If you're behind a proxy or in a region with egress rules, the SDK's internal curl call may be the only place to change it — check whether the bundle exposes it; often it doesn't, another argument for the direct SDK.
  • Service ID confusion. The registered ID is not guaranteed to be mandrill. Dump the container (bin/console debug:container mandrill) or read services.xml before injecting by string.
  • Webhook verification is order-sensitive. Sort $_POST with ksort, concatenate key+value with no separators, HMAC-SHA1 with the webhook key (not the API key), base64-encode, and compare with hash_equals. The URL must match exactly what you registered, including scheme and trailing slash.
  • Inbound email arrives as application/x-www-form-urlencoded with a mandrill_events JSON blob — not JSON body. $request->input('mandrill_events') (Laravel) or $_POST['mandrill_events'] (Symfony), then json_decode.
  • Rate limits and batching. Limits are per-account and hourly/daily, not just per-second. Batch to 1000 per call and back off on HTTP 429 — but also watch the returned reject_reason for quota-related rejections, which come back as 200s.
  • Extension point. If you need to customize, the cleanest seam is to define your own service aliasing the SDK client and skip the bundle's wrapper entirely — the wrapper adds little and obscures sub-object access ($client->messages, $client->templates, $client->users, $client->inbound).
  • Given 0 stars and 0 dependents, assume no security patches, no PHP 8 compatibility work, and no docs beyond the README. Budget for vendoring or replacing it rather than relying on upstream fixes.
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.
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package