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

rezzza/mailchimp-bundle

Symfony bundle that wraps the MailChimp API, providing ready-to-use services and configuration for managing lists, subscribers, and campaigns from your application. Suitable for legacy Symfony projects; note the small user base and limited recent maintenance.

View on GitHub
Deep Wiki
Context7

Getting Started

rezzza/mailchimp-bundle is a Symfony 2 bundle, not a Laravel package. There is no service provider, no facade, and no config/mailchimp.php convention you can publish. A Laravel developer should treat the repository as a reference implementation for wiring Mailchimp into a container, not as something to composer require into a Laravel app (its constraints on symfony/symfony ~2.3 and PHP 5.x will conflict with modern Laravel).

Minimal steps to evaluate and reuse it:

  1. Open composer.json and identify the underlying Mailchimp client it depends on (older releases wrap the Mailchimp API v1.3/2.0 client; the bundle itself mostly provides DI configuration and a thin service).
  2. Read DependencyInjection/Configuration.php — this is where the supported config keys live (api_key, list IDs, default list, double opt-in flags, etc.). That tree is the actual "API surface" of the bundle.
  3. Read the extension and service definitions to see the service ID it registers and how the client is constructed (API key + data center).
  4. Port that idea into Laravel: add an entry to config/services.php, bind a singleton in a service provider, and inject it where needed.

First practical use case — subscribe a user to a list:

// config/services.php
'mailchimp' => [
    'key'  => env('MAILCHIMP_API_KEY'), // e.g. abc123...-us10
    'list' => env('MAILCHIMP_LIST_ID'),
],
// app/Providers/MailchimpServiceProvider.php
public function register(): void
{
    $this->app->singleton(MailchimpClient::class, fn () => new MailchimpClient(
        config('services.mailchimp.key'),
        config('services.mailchimp.list'),
    ));
}
app(MailchimpClient::class)->subscribe(
    email: $user->email,
    mergeFields: ['FNAME' => $user->first_name, 'LNAME' => $user->last_name],
    doubleOptIn: false,
);

If you are starting fresh, skip the bundle entirely and use mailchimp/mailchimp-marketing (API v3) or drewm/mailchimp-api. The bundle's value today is mostly in showing the shape of a clean abstraction: config in one place, a single injected service, list defaults.

Implementation Patterns

Service-provider wrapping. Mirror the bundle's DI extension by registering a singleton that owns the HTTP client and the default list. Keep the Mailchimp client out of controllers.

Dedicated repository/service for list operations. Rather than sprinkling ->post() calls, expose intent methods:

class MailchimpSubscriber
{
    public function __construct(private MailchimpClient $client) {}

    public function subscribe(User $user): void { /* ... */ }
    public function unsubscribe(string $email): void { /* ... */ }
    public function updateMergeFields(string $email, array $fields): void { /* ... */ }
    public function addTag(string $email, string $tag): void { /* ... */ }
}

Model events for synchronization. Hook created / updated on the model that represents the subscriber, but always push to a queue. Mailchimp calls are network I/O and will slow requests:

User::created(fn (User $user) => SyncToMailchimp::dispatch($user));

Queued jobs for bulk operations. Use batch endpoints (or chunked jobs) rather than a loop of individual requests. The bundle-era API used /batch-subscribe; in v3 you use the batch endpoint with operations. Either way, keep each job under a few hundred members.

Webhooks as the write-back path. The bundle-era setup assumed the app was the source of truth. Modern Mailchimp is bidirectional: add a POST /webhooks/mailchimp route, verify the secret, and reconcile unsubscribes/bounces back into your database. This is the cleanest way to keep local state in sync without polling.

Testing with a fake. Bind an interface (MailchimpGateway) to a fake in tests so no test hits the network:

$this->app->instance(MailchimpGateway::class, new FakeMailchimpGateway());

Config surface to copy from the bundle. The Symfony Configuration class is a good template: default list, API key, double opt-in boolean, merge field map. Reproduce those in config/services.php rather than hardcoding list IDs in services.

Gotchas and Tips

  • This is not installable in modern Laravel. The Symfony 2 constraints and PHP 5.x requirement will not resolve against Laravel 8+. Do not attempt to register it as a package; port the configuration concept instead.
  • API version drift is the biggest risk. The package last shipped in 2015 and targets Mailchimp API v1.3/2.0. Those endpoints are retired. Any code copied from it must be rewritten for v3.0 (/3.0/lists/{list_id}/members/{subscriber_hash}).
  • The API key encodes the data center. The suffix after the dash (-us10, -eu1) determines the hostname (https://us10.api.mailchimp.com). Hardcoding https://api.mailchimp.com will fail for non-default data centers. Parse the suffix from the key at boot and use it in the client base URI.
  • subscriber_hash is the MD5 of the lowercased email. Don't pass the raw email to path endpoints — lowercase and hash it, or you'll get 404s for mixed-case addresses.
  • Error 232 means "already subscribed." Treat it as success when the intent is "ensure subscribed," not as an exception. Same for 404 (MemberNotExist) on unsubscribe — make these idempotent in your service methods.
  • Double opt-in is a per-request flag. If the bundle config set double_opt_in: true globally, remember that v3 requires status: 'pending' vs 'subscribed' per member. Be explicit rather than relying on a global default.
  • Merge field keys are uppercase and must exist in the audience. If you send fname or a tag that hasn't been defined, Mailchimp silently drops it (or errors depending on API version). Validate against a cached list of merge fields at deploy time.
  • Rate limits are 10 concurrent requests. Long-running sync loops will hit 429s. Use usleep between calls, a queue with limited workers, or the batch endpoint. The bundle gives no retry logic — add exponential backoff in your HTTP layer.
  • Cache list metadata. Fetching merge fields, tags, and segments on every webhook or sync call wastes quota. Cache for hours, invalidate on webhook.
  • Verify webhook authenticity. Mailchimp does not sign webhooks by default; use a secret query parameter or basic auth on the endpoint and compare against config('services.mailchimp.webhook_secret'). Reject anything without it.
  • Extension points worth borrowing: the bundle's Configuration tree (a clean config blueprint), the single-service abstraction (easy to swap clients), and the separation of "list operations" from transport. Everything else — the Symfony DI wiring, the event dispatcher integration — is not reusable in Laravel.
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.
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
frankyso/ipaymu
3mdikram/worldmoneywords
snowsoft/config
itmosoft/laravel-subscriptions
larva/laravel-ai-qwen
adachsoft/api-version-bundle