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

mlpz/mailchimp-bundle

A Symfony bundle that integrates the Mailchimp API, providing service wrappers to manage audiences, members, and subscriptions from your PHP application. Useful for newsletter signups and list synchronization.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a Symfony bundle, not a Laravel package. There is no service provider, no facade, no auto-discovery, and no config/mailchimp.php. Treat it as a library of classes you may be able to wire up manually — not as a drop-in Laravel dependency. Before writing any application code, do a 15-minute feasibility pass.

The latest release (v1.3) changes exactly one thing: it adds a deprecation notice for API v1. It is not a fix, not a v3 migration, and not a Laravel compatibility patch. Read it as a confirmation of what the previous assessment suspected: this bundle talks to a retired API.

Minimal steps

  1. Check installability first. In a throwaway branch:

    composer require mlpz/mailchimp-bundle --dry-run
    

    The package dates from 2014. Expect conflicts with modern symfony/* components, PHP 8, and possibly PSR-4 autoload mismatches. If Composer refuses, stop here — the cost of forcing it is higher than rewriting the integration.

  2. Read the bundle source in this order (once installed, under vendor/mlpz/mailchimp-bundle/):

    • README.md — the only usage docs that exist.
    • CHANGELOG.md / git tags — v1.3 is the "add deprecating message for API v1" release; expect a trigger_error/E_USER_DEPRECATED call somewhere on the request path.
    • DependencyInjection/Configuration.php — the real config schema (api_key, list defaults, etc.).
    • DependencyInjection/*Extension.php — shows the service ID and which class it instantiates.
    • Services/ — the wrapper class exposing subscribe(), unsubscribe(), batchSubscribe(), etc. This is the only part you actually care about.
  3. Do not try to boot the bundle. Laravel has no Kernel::registerBundles(). Instead, instantiate the service class yourself in a service provider and bind it to the container:

    // config/services.php
    'mailchimp' => [
        'key'     => env('MAILCHIMP_API_KEY'),
        'list_id' => env('MAILCHIMP_LIST_ID'),
    ],
    
    // app/Providers/AppServiceProvider.php
    public function register(): void
    {
        $this->app->singleton(\MZ\MailChimpBundle\Services\MailChimp::class, function () {
            return new \MZ\MailChimpBundle\Services\MailChimp(
                config('services.mailchimp.key')
            );
        });
    }
    

    Confirm the constructor signature against the actual source — it may expect a full config array or a pre-built client rather than a bare API key.

  4. First use case: subscribe on registration. Wire a queued listener on Registered, resolve the bound service, subscribe the user's email to a dedicated test audience. If that round-trips successfully, the rest is mechanical. If it returns 404/410 — or throws the new deprecation as an ErrorException (see gotchas) — you've hit the API-version wall and should migrate rather than debug.

Where to look first when something breaks: Services/ for the call signature, then the underlying HTTP call it makes, then grep the release diff for the new deprecation trigger_error. Nine times out of ten the failure is the endpoint/version, not your code.

Implementation Patterns

Wrap it, never call it directly. The bundle's service class leaks MailChimp-specific method signatures and exception types all over your codebase. Put one adapter behind an interface so you can swap the transport later — this matters more now that the vendor has publicly acknowledged the API it targets is deprecated:

interface Newsletter
{
    public function subscribe(string $email, array $mergeFields = []): bool;
    public function unsubscribe(string $email): bool;
}
final class BundleNewsletter implements Newsletter
{
    public function __construct(
        private \MZ\MailChimpBundle\Services\MailChimp $client,
        private string $listId,
    ) {}

    public function subscribe(string $email, array $mergeFields = []): bool
    {
        try {
            $this->client->subscribe(
                $this->listId,
                strtolower(trim($email)),
                $mergeFields,
                'html',
                false // single opt-in; see gotchas
            );
            return true;
        } catch (\Exception $e) {
            report($e);
            return false;
        }
    }
}

Always subscribe from a queued job. MailChimp calls are slow and flaky. Never block a registration request on them:

class SyncSubscriber implements ShouldQueue
{
    public function handle(Newsletter $newsletter): void
    {
        $newsletter->subscribe($this->user->email, [
            'FNAME' => $this->user->first_name,
        ]);
    }
}

Treat integration as event-driven, not inline. UserRegistered → listener → job, and UserUpdated → job when email or name changes. This keeps the MailChimp dependency at the edge of the app and makes it trivial to disable in tests.

Idempotency is your responsibility. Registration retries, double-clicks, and replayed queue jobs all produce duplicate subscribe calls. Design the adapter to treat "already subscribed" as success rather than an error (log at debug, return true).

Config resolution. Read everything from config/services.php backed by .env. The API key encodes the datacenter as its suffix after the last - (...-us14). If you ever fall back to raw HTTP calls, you need that segment in the host (us14.api.mailchimp.com).

Testing. Bind a fake Newsletter implementation in the test container. Do not let a unit test touch the bundle's client — it will attempt real DNS resolution and fail in CI. For any raw HTTP you add yourself, use Http::fake().

Extension point. If you must customise behaviour (retry policy, logging, field mapping), decorate the bundle service rather than editing vendor files, and put all field-mapping logic in your adapter. That mapping layer is exactly what you'll carry over to a modern SDK, so keep it isolated.

Plan the exit now. v1.3 is a tombstone, not a lifeline. Budget the migration to mailchimp/marketing or drewm/mailchimp-api in the same sprint as the integration work, and keep every call site behind the Newsletter interface so the swap is a one-file diff.

Gotchas and Tips

  • v1.3 adds a deprecation notice — that is the whole release. It confirms the bundle calls MailChimp API v1, which is retired. No endpoint fixes, no v3 support, no Laravel support. The only thing that changed is that the package now tells you it's broken.
  • The new deprecation can throw in Laravel. If the release calls trigger_error(..., E_USER_DEPRECATED), Laravel's exception handler converts any reported error level — including deprecations — into an ErrorException. On a default E_ALL setup that turns a previously working subscribe call into a thrown exception inside your queued job. Wrap the call in your adapter's try/catch, or add E_USER_DEPRECATED to error_reporting exclusions in the environment where you still run this bundle.
  • Archived since 2014 and unmaintained. A one-line deprecation commit is not maintenance. Nobody will fix a PHP 8 incompatibility, a v3 endpoint, or a security issue for you. Assume you own every bug.
  • API version mismatch is the dealbreaker. The bundle targets v1/v2 endpoints (/1.3/, /2.0/), which are retired. The v3 API uses different paths (/3.0/lists/{list_id}/members), different auth (HTTP Basic with any username and the API key as password), and different payloads. No amount of clean wiring makes v1 calls succeed.
  • Symfony container assumptions. The bundle's services reference service_container, %parameters%, and Symfony event dispatchers. Manually instantiating the wrapper class is usually fine; trying to use its DI extension from Laravel is not.
  • PHP 8 fatal errors. Old code may use each(), create_function(), or untyped properties removed in PHP 8. Run php -l over the Services/ directory before assuming it loads.
  • Double opt-in default. v1/v2 subscribe() defaulted to double_optin = true, meaning users get a confirmation email. Pass false explicitly if you've already captured consent, or your "subscribed" users will silently sit in pending.
  • list vs audience. Old docs and method names say "list"; the current UI says "audience". Same thing. Don't go looking for a separate "audience" parameter.
  • Merge field casing matters. FNAME, LNAME are uppercase in the API but the UI may display them capitalised. Mismatched keys are silently ignored rather than rejected — a classic "why is the name blank" bug. Verify field names in the audience's Settings → Audience fields and merge tags.
  • Email normalisation. Lowercase and trim before sending. MailChimp treats [email protected] and [email protected] as the same member; if you don't normalise, your local records won't match theirs and dedupe logic breaks.
  • "Member exists" is an error response. The API returns HTTP 400 with title: "Member Exists". Catch and swallow it — this is expected on re-sync, not a failure.
  • Rate limits. v3 allows ~10 concurrent requests per key. Batch endpoints cap at 500 operations per call. If you're syncing an existing user table, chunk it and add backoff.
  • Logging and debugging. Log the request payload and response body at debug level, but never log the API key. The key grants full account access — one leaked log line and your audience is gone. The new deprecation message is safe to log; the config array it may dump alongside it is not.
  • Migration path: replace with mailchimp/marketing (official v3 SDK) or drewm/mailchimp-api, keep your Newsletter interface, and delete the adapter's internals. Your call sites — jobs, listeners, controllers — should not change at all. Given v1.3's deprecation notice, treat this as scheduled work rather than a contingency.
  • Consent and compliance. Store the consent timestamp and source locally. MailChimp's own audit trail is not a substitute for your own records under GDPR/CAN-SPAM, and an archived client won't help you demonstrate anything.
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.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle