PHPackages                             x-laravel/listmonk - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Mail &amp; Notifications](/categories/mail)
4. /
5. x-laravel/listmonk

ActiveLibrary[Mail &amp; Notifications](/categories/mail)

x-laravel/listmonk
==================

Laravel integration for Listmonk - Self-hosted newsletter and mailing list manager

v1.0.0(4mo ago)07↓93.8%MITPHPPHP ^8.1

Since Feb 15Pushed 4mo agoCompare

[ Source](https://github.com/x-laravel/listmonk)[ Packagist](https://packagist.org/packages/x-laravel/listmonk)[ RSS](/packages/x-laravel-listmonk/feed)WikiDiscussions master Synced today

READMEChangelogDependencies (6)Versions (2)Used By (0)

Listmonk for Laravel
====================

[](#listmonk-for-laravel)

A Laravel package for integrating with [Listmonk](https://listmonk.app) — the self-hosted newsletter and mailing list manager.

Provides a clean API wrapper for Listmonk's REST API, automatic model-to-subscriber synchronization, queue support, and Eloquent lifecycle hooks.

Requirements
------------

[](#requirements)

- PHP 8.1+
- Laravel 10 or 11
- A running Listmonk instance

Installation
------------

[](#installation)

```
composer require x-laravel/listmonk
```

Publish the configuration file:

```
php artisan vendor:publish --tag=listmonk-config
```

Add the following to your `.env`:

```
LISTMONK_BASE_URL=https://listmonk.example.com
LISTMONK_API_USER=your-api-user
LISTMONK_API_TOKEN=your-api-token
```

Configuration
-------------

[](#configuration)

```
# API
LISTMONK_BASE_URL=https://listmonk.example.com
LISTMONK_API_USER=
LISTMONK_API_TOKEN=

# Subscriptions
LISTMONK_PRECONFIRM_SUBSCRIPTIONS=true

# Queue
LISTMONK_QUEUE_ENABLED=true
LISTMONK_QUEUE_CONNECTION=null
LISTMONK_QUEUE_NAME=null
LISTMONK_QUEUE_DELAY=0
LISTMONK_QUEUE_TRIES=3
LISTMONK_QUEUE_BACKOFF=10,30,60

# Passive list (move deleted users here instead of unsubscribing)
LISTMONK_PASSIVE_LIST_ID=null

# What to do with old email when a user changes their email
# Options: "delete" or "passive"
LISTMONK_EMAIL_CHANGE_BEHAVIOR=delete
```

Quick Start
-----------

[](#quick-start)

### 1. Implement the interface and trait on your model

[](#1-implement-the-interface-and-trait-on-your-model)

```
use XLaravel\Listmonk\Contracts\NewsletterSubscriber;
use XLaravel\Listmonk\Traits\InteractsWithNewsletter;

class User extends Authenticatable implements NewsletterSubscriber
{
    use InteractsWithNewsletter;
}
```

That's it. The package will automatically sync your model to Listmonk on `created`, `updated`, `deleted`, and `restored` events.

### 2. Customize (optional)

[](#2-customize-optional)

Override trait methods in your model to customize behavior:

```
class User extends Authenticatable implements NewsletterSubscriber
{
    use InteractsWithNewsletter;

    // Custom email column
    protected string $newsletterEmailColumn = 'email_address';

    // Custom name column
    public function getNewsletterNameColumn(): string
    {
        return 'full_name';
    }

    // Custom list IDs
    public function getNewsletterLists(): array
    {
        $lists = [1]; // Main newsletter

        if ($this->is_premium) {
            $lists[] = 2; // Premium list
        }

        return $lists;
    }

    // Custom attributes synced to Listmonk
    public function getNewsletterAttributes(): array
    {
        return [
            'plan' => $this->subscription_plan ?? '',
            'country' => $this->country ?? '',
            'registered_at' => $this->created_at?->toIso8601String(),
        ];
    }

    // Custom passive list per model
    public function getNewsletterPassiveListId(): ?int
    {
        return 5;
    }
}
```

API Usage
---------

[](#api-usage)

The package exposes three services through the `Listmonk` facade:

### Subscribers API (raw wrapper)

[](#subscribers-api-raw-wrapper)

```
use XLaravel\Listmonk\Facades\Listmonk;

// List subscribers
Listmonk::subscribers()->get(query: "subscribers.email LIKE '%@example.com%'");

// Find by ID
Listmonk::subscribers()->find(42);

// Create
Listmonk::subscribers()->create([
    'email' => 'user@example.com',
    'name' => 'John Doe',
    'lists' => [1, 2],
    'status' => 'enabled',
    'preconfirm_subscriptions' => true,
]);

// Update
Listmonk::subscribers()->update(42, [
    'name' => 'Jane Doe',
    'lists' => [1, 2, 3],
]);

// Delete
Listmonk::subscribers()->delete(42);
Listmonk::subscribers()->deleteMany([42, 43, 44]);

// Manage lists
Listmonk::subscribers()->updateList(
    subscriberIds: [42, 43],
    listIds: [1, 2],
    action: 'add' // 'add', 'remove', or 'unsubscribe'
);

// Other operations
Listmonk::subscribers()->blocklist(42);
Listmonk::subscribers()->export(42);
Listmonk::subscribers()->bounces(42);
Listmonk::subscribers()->deleteBounces(42);
Listmonk::subscribers()->sendOptin(42);
```

### Lists API (raw wrapper)

[](#lists-api-raw-wrapper)

```
Listmonk::lists()->get();
Listmonk::lists()->get(query: 'newsletter', status: 'enabled', minimal: true);
Listmonk::lists()->find(1);
Listmonk::lists()->create(['name' => 'My List', 'type' => 'public']);
Listmonk::lists()->update(1, ['name' => 'Updated List']);
Listmonk::lists()->delete(1);
```

### Newsletter Manager (business logic)

[](#newsletter-manager-business-logic)

```
// Sync a model (create or update in Listmonk)
Listmonk::newsletter()->sync($user);

// Partial update (only specified fields)
Listmonk::newsletter()->updatePartial($user, ['name']);

// Unsubscribe (delete from Listmonk)
Listmonk::newsletter()->unsubscribe($user);
Listmonk::newsletter()->unsubscribeByEmail('old@example.com');

// Move to passive list
Listmonk::newsletter()->moveToPassiveList($user, passiveListId: 5);
Listmonk::newsletter()->moveToPassiveListByEmail('old@example.com', passiveListId: 5);

// Batch sync
$results = Listmonk::newsletter()->syncMany(User::all());
// ['synced' => 95, 'failed' => 5, 'errors' => [...]]
```

### Helper function

[](#helper-function)

```
listmonk()->subscribers()->find(42);
listmonk()->newsletter()->sync($user);
```

Model Actions
-------------

[](#model-actions)

Models using the `InteractsWithNewsletter` trait get these methods:

```
$user->subscribeToNewsletter();
$user->unsubscribeFromNewsletter();
$user->updateNewsletterSubscription();
$user->moveToPassiveList();
```

All respect the `LISTMONK_QUEUE_ENABLED` setting — when enabled, operations are dispatched as queued jobs.

### Temporarily disable sync

[](#temporarily-disable-sync)

```
User::withoutNewsletterSync(function () {
    $user->update(['email' => 'new@example.com']);
    // No Listmonk API calls will be made
});
```

Events
------

[](#events)

EventWhen`SubscriberSubscribed`New subscriber created in Listmonk`SubscriberSynced`Existing subscriber updated in Listmonk`SubscriberUnsubscribed`Subscriber deleted from Listmonk`SubscriberSyncFailed`Sync failed (with exception)```
use XLaravel\Listmonk\Events\SubscriberSubscribed;

class SendWelcomeEmail
{
    public function handle(SubscriberSubscribed $event): void
    {
        $model = $event->model;
        $apiResponse = $event->response;
    }
}
```

Artisan Commands
----------------

[](#artisan-commands)

```
# Check API connectivity
php artisan listmonk:health

# Sync all subscribers
php artisan listmonk:sync

# Sync a specific model
php artisan listmonk:sync "App\Models\Customer"

# With options
php artisan listmonk:sync --chunk=200 --force --dry-run
```

Testing
-------

[](#testing)

The package provides a test trait for faking API calls:

```
use XLaravel\Listmonk\Testing\InteractsWithListmonk;

class MyTest extends TestCase
{
    use InteractsWithListmonk;

    public function test_user_subscribes(): void
    {
        $this->fakeListmonk();

        $user = User::factory()->create();

        $this->assertSubscriberSynced($user->email);
    }

    public function test_with_existing_subscriber(): void
    {
        $this->fakeListmonkWithSubscriber([
            'id' => 1,
            'email' => 'user@example.com',
            'name' => 'John',
            'lists' => [['id' => 1]],
            'attribs' => [],
            'status' => 'enabled',
        ]);

        // ...
    }

    public function test_api_failure(): void
    {
        $this->fakeListmonkFailure(500, 'Internal Server Error');

        // ...
    }
}
```

Architecture
------------

[](#architecture)

```
src/
├── Concerns/
│   ├── MakesApiCalls.php         # Shared API error handling
│   └── ConfiguresQueue.php       # Shared job queue configuration
├── Contracts/
│   └── NewsletterSubscriber.php  # Interface for syncable models
├── Console/
│   ├── ListmonkHealthCommand.php
│   └── SyncSubscribersCommand.php
├── Events/
│   ├── SubscriberSubscribed.php
│   ├── SubscriberSynced.php
│   ├── SubscriberSyncFailed.php
│   └── SubscriberUnsubscribed.php
├── Exceptions/
│   ├── ListmonkException.php
│   ├── ListmonkApiException.php
│   └── ListmonkConnectionException.php
├── Facades/
│   └── Listmonk.php
├── Jobs/
│   ├── SubscribeJob.php
│   ├── UnsubscribeJob.php
│   ├── UnsubscribeJobByEmail.php
│   ├── UpdateSubscriptionJob.php
│   └── MoveToPassiveListJobByEmail.php
├── Observers/
│   └── NewsletterSubscriberObserver.php
├── Services/
│   ├── Subscribers.php           # Listmonk Subscribers API wrapper
│   ├── Lists.php                 # Listmonk Lists API wrapper
│   └── NewsletterManager.php     # Business logic (sync, merge, events)
├── Testing/
│   └── InteractsWithListmonk.php
├── Traits/
│   └── InteractsWithNewsletter.php
├── Listmonk.php                  # Main service
├── ListmonkServiceProvider.php
└── helpers.php

```

License
-------

[](#license)

MIT

###  Health Score

34

—

LowBetter than 75% of packages

Maintenance75

Regular maintenance activity

Popularity4

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity43

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

139d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/2bdb64c6c087c331b8bd5906bb1aa7eb06bc83af3654a48ba8ab9da365976651?d=identicon)[X-Adam](/maintainers/X-Adam)

---

Top Contributors

[![x-adam](https://avatars.githubusercontent.com/u/60411758?v=4)](https://github.com/x-adam "x-adam (19 commits)")

---

Tags

laravelemailmailing listsubscriptionnewsletterlistmonk

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/x-laravel-listmonk/health.svg)

```
[![Health](https://phpackages.com/badges/x-laravel-listmonk/health.svg)](https://phpackages.com/packages/x-laravel-listmonk)
```

###  Alternatives

[laravel/scout

Laravel Scout provides a driver based solution to searching your Eloquent models.

1.7k55.0M618](/packages/laravel-scout)[laravel/pulse

Laravel Pulse is a real-time application performance monitoring tool and dashboard for your Laravel application.

1.7k15.1M132](/packages/laravel-pulse)[psalm/plugin-laravel

Psalm plugin for Laravel

3355.3M346](/packages/psalm-plugin-laravel)[illuminate/auth

The Illuminate Auth package.

10528.2M1.2k](/packages/illuminate-auth)[roots/acorn

Framework for Roots WordPress projects built with Laravel components.

9762.4M131](/packages/roots-acorn)[illuminate/notifications

The Illuminate Notifications package.

513.1M1.1k](/packages/illuminate-notifications)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
