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

Mailchimp Bundle Laravel Package

wunderdata/mailchimp-bundle

Symfony bundle that integrates the Mailchimp API into your app, with configurable services for lists, members, subscriptions, and webhooks so you can manage audiences and automate Mailchimp workflows from PHP.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a Symfony2 bundle, not a Laravel package. There is no service provider, no facade, no config/mailchimp.php, and no Laravel auto-discovery. Before writing any code, accept one of two realities:

  1. You are not going to install the bundle in Laravel. Pull the underlying API client classes (the Mailchimp / MailchimpExport wrappers in src/) into your app, or just use a maintained client. This is almost always the right call.
  2. You are maintaining a legacy Symfony app and only need to understand it well enough to migrate off.

Either way, the first thing to do is read Resources/config/services.xml and DependencyInjection/Configuration.php. Those two files tell you the exact service IDs, the constructor arguments (API key, whether SSL is forced), and the config tree shape. Everything else in the bundle is thin glue over the Mailchimp v2.0 and Export v1.0 APIs.

Minimal path if you insist on reusing the client classes inside Laravel:

composer require wunderdata/mailchimp-bundle

Then, in config/services.php:

'mailchimp' => [
    'api_key' => env('MAILCHIMP_API_KEY'),
    'ssl'     => true,
],

Bind the client in a service provider:

$this->app->singleton(\Wunderdata\MailchimpBundle\Mailchimp::class, function ($app) {
    return new \Wunderdata\MailchimpBundle\Mailchimp(
        config('services.mailchimp.api_key'),
        config('services.mailchimp.ssl')
    );
});

Your first use case should be the cheapest possible round-trip: call the "ping" / account-details method and dump the response. That validates three things at once — the key format (it must end in -usX), network/SSL, and that the v2 endpoint still answers for your account. Do not start with list subscriptions; you will conflate auth failures with merge-var validation errors.

A realistic first task, if the API still responds for you, is subscribing an email to a list with a double opt-in flag and reading back the member's leid. That exercises the list methods and member methods and tells you how the client surfaces errors.

Implementation Patterns

Wrap it, don't scatter it. The bundle's client returns raw associative arrays and throws generic exceptions. Put a single MailchimpService around it with typed methods (subscribe(string $listId, string $email, array $mergeVars): void, unsubscribe(...), memberInfo(...)). Every call site in your app talks to your class, never the vendor object. This is what makes the inevitable rip-and-replace to Mailchimp Marketing v3 a one-file change instead of a grep-and-pray exercise.

Inject via constructor, resolve via container. Register the vendor client as a singleton and inject your wrapper. The bundle's Symfony equivalent is @mailchimp (verify the ID in services.xml); in Laravel you are rebuilding that wiring by hand in a service provider.

Queue every write. Subscribes, unsubscribes, tag updates, and ecommerce calls should all be queued jobs. Mailchimp v2 is rate-limited (roughly 120 requests/minute per account) and network latency to the datacenter endpoint is real. A SubscribeToMailchimp job with $tries = 3 and exponential backoff ([10, 60, 300]) is the difference between a resilient integration and a checkout flow that times out when Mailchimp hiccups.

Batch where the API allows. The v2 batch endpoint accepts an array of operations and returns a batch_id; the Export API works the same way. Submit, persist the ID, poll from a scheduled command, then reconcile results. Do not poll in a loop inside a web request.

Treat membership checks as read-through cache. memberInfo is cheap but not free. Cache list membership and merge-var snapshots in Redis for a few minutes if you make routing decisions based on them (e.g., "show the newsletter upsell only to non-subscribers").

Integration tip — webhooks beat polling. Configure Mailchimp webhooks to hit a Laravel route for subscribe/unsubscribe/profile/cleaned events, and let that route update your local user record. This keeps your database authoritative without hammering a deprecated API. Verify the payload type field and never trust the request without checking against a known list ID.

Ecommerce360 pattern. If the legacy app used the bundle's ecommerce helpers (order add/update/delete), the ordering matters: add the order, add its lines, then add the customer mapping. These are separate calls and partial failure leaves orphaned order records — wrap them in an idempotent job keyed on your local order ID.

Gotchas and Tips

The API this wraps is dead. Mailchimp v2.0 and Export v1.0 were superseded by Marketing API v3 in 2014 and have been fully retired. Any method in this bundle targeting /2.0/ or /export/1.0/ will 404 or return a "wrong version" error today. Confirm this against your own account before planning any work around it — it is the single fact that should drive your decision.

Zero stars, zero dependents, no maintenance. There are no users to find answers from, no issue tracker activity to learn from, and no releases fixing anything. Budget for reading the source rather than Googling.

No Laravel package discovery. composer require will not register anything. The bundle's MailchimpBundle class extends Symfony's Bundle and expects a kernel to boot it — instantiating it in Laravel does nothing useful. Extract the client classes or use drewm/mailchimp-api / Mailchimp's official mailchimp-marketing SDK instead.

API key format matters. Keys are <32 hex>-<dc>, e.g. abc123-us14. The datacenter suffix is not decoration — the v2 client derives the endpoint host from it. A key without a suffix, or with a wrong one, fails at the transport layer and looks like an auth error.

Forced SSL is a config quirk. The bundle exposes an ssl flag, and some versions default it based on the Symfony kernel environment. Explicitly set it to true; there is no scenario where plaintext is correct.

Error handling is blunt. The client throws on any non-2xx with the raw Mailchimp error string, and Mailchimp v2 returns {"status": "error", "code": 214, "name": "List_AlreadySubscribed"} style bodies. Parse code and name, don't string-match the message. Code 214 (already subscribed) is a success in disguise for most signup flows — normalize it in your wrapper so callers don't have to.

merge_vars casing is inconsistent. v2 expects uppercase merge tags (FNAME, LNAME) inside the merge_vars array, but the list's merge-field definitions come back with mixed case. Build a small normalizer; otherwise you get silent failures where the subscribe succeeds but fields are blank.

Double opt-in is a server-side setting, not a request parameter. Passing double_optin in the payload only works if the list permits it. Don't assume your code controls the confirmation email — check the list config.

The Export API is asynchronous and lossy. You get a chunked file handle, not JSON. Poll until finished is true, and be aware that a second export call with the same parameters can return the same cached export. Store the export ID or you will re-download the same stale data.

Debugging tip. The client exposes the last request/response in some versions; if not, subclass it and log before/after the transport call. With the API retired, wire-level logs are the only way to distinguish "wrong endpoint" from "bad key."

Extension points are minimal. There is no driver abstraction, no HTTP client injection, no event system. The realistic extension point is the service definition in services.xml (Symfony) or your own wrapper class (Laravel). Use the wrapper as the seam for caching, retries, and error normalization.

Migration advice. If this package is in your dependency tree, treat it as a migration task, not an integration task. Map each method you call to its v3 equivalent (lists/{id}/members, /3.0/batches, /3.0/lists/{id}/members/{hash} for single-member ops), swap in a current SDK, and route traffic through the wrapper you built. The wrapper is the only part of this work that survives.

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.
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
cgv/localized-resource