PHPackages                             mydnic/laravel-subscribers - 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. [Utility &amp; Helpers](/categories/utility)
4. /
5. mydnic/laravel-subscribers

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

mydnic/laravel-subscribers
==========================

Easily Manage Internal Newsletter Subscribers in Laravel — with campaigns, mail sending, and tracking

v1.9.1(1y ago)264.8k—0%5MITPHPPHP ^7.1|8.\*CI passing

Since Jan 24Pushed 1mo ago1 watchersCompare

[ Source](https://github.com/mydnic/kanpen)[ Packagist](https://packagist.org/packages/mydnic/laravel-subscribers)[ Docs](https://github.com/mydnic/laravel-subscribers)[ GitHub Sponsors](https://github.com/Mydnic)[ RSS](/packages/mydnic-laravel-subscribers/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (10)Dependencies (4)Versions (23)Used By (0)

Kanpen
======

[](#kanpen)

[![Latest Version on Packagist](https://camo.githubusercontent.com/d2224ac047b6b71d13a723d364cb6ca9764f5267ba04f4dcb4ea16fc8d166d4b/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6d79646e69632f6b616e70656e2e737667)](https://packagist.org/packages/mydnic/kanpen)[![Software License](https://camo.githubusercontent.com/074b89bca64d3edc93a1db6c7e3b1636b874540ba91d66367c0e5e354c56d0ea/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d627269676874677265656e2e737667)](LICENSE)[![PHP](https://camo.githubusercontent.com/83dd395020c37276225039739320f6c8e7e99963ab21ee3d09282cb48dad2a60/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048502d382e312532422d626c7565)](https://php.net)[![Laravel](https://camo.githubusercontent.com/934c60d4b198c50fe53587c7ef11138695a83b6f668b40ef8f995dab4ac7b805/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4c61726176656c2d3130253230253743253230313125323025374325323031322d726564)](https://laravel.com)[![Filament](https://camo.githubusercontent.com/790ac48c2bf73949b16075628261c73e6f77365e5809854d6105a3d3a91a366e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f46696c616d656e742d3325323025374325323034253230253743253230352d6f72616e6765)](https://filamentphp.com)

A lightweight newsletter subscriber management package for Laravel. Handle subscriptions, send campaigns, track opens and clicks — all without a third-party service.

> **Heads-up:** This package is designed for small to medium audiences (think side-projects, indie apps, internal tools). It sends mail through whatever driver is configured in your `config/mail.php` and has **no bounce handling, no complaint webhooks, and no deliverability tooling**. If you're sending to tens of thousands of subscribers or need professional deliverability guarantees, use a dedicated email service provider instead. [Sendboo](https://sendboo.com) is a great option with full campaign management, AI features, and solid deliverability.

---

Features
--------

[](#features)

- **Subscriber management** — subscribe, unsubscribe, soft-delete, restore
- **Email verification** — optional double opt-in with signed URLs
- **Campaigns** — create and send HTML newsletters to all subscribers via Laravel queues
- **Open &amp; click tracking** — pixel-based open tracking and link proxy click tracking
- **User sync** — automatically sync your `User` model with the subscribers table via a trait or Artisan command
- **Publishable views** — override the email layout and unsubscribe page in your own app
- **Nova integration** — Laravel Nova resource and metrics card included
- **Filament integration** — full Filament plugin with resources, infolists, and widgets
- **Events** — every action fires an event you can listen to

---

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

[](#requirements)

- PHP 8.1+
- Laravel &gt;= 10

---

Table of Contents
-----------------

[](#table-of-contents)

- [Installation](#installation)
- [Configuration](#configuration)
- [Subscriber Management](#subscriber-management)
    - [Web Form](#web-form)
    - [API Endpoint](#api-endpoint)
    - [Programmatic Subscription](#programmatic-subscription)
    - [Email Verification](#email-verification)
    - [Unsubscribing](#unsubscribing)
- [Campaigns](#campaigns)
    - [Creating a Campaign](#creating-a-campaign)
    - [Sending a Campaign](#sending-a-campaign)
    - [Scheduling a Campaign](#scheduling-a-campaign)
    - [Custom Blade Views](#custom-blade-views)
    - [Campaign API](#campaign-api)
- [Tracking](#tracking)
    - [How It Works](#how-it-works)
    - [Tracking Events](#tracking-events)
- [User Sync](#user-sync)
    - [HasNewsletterSubscription Trait](#hasnewslettersubscription-trait)
    - [Artisan Sync Command](#artisan-sync-command)
- [Events Reference](#events-reference)
- [Publishing Assets](#publishing-assets)
- [Nova Integration](#nova-integration)
- [Filament Integration](#filament-integration)
- [Upgrading](#upgrading)

---

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

[](#installation)

Install via Composer:

```
composer require mydnic/kanpen
```

The service provider is auto-discovered. Next, publish and run the migrations:

```
php artisan vendor:publish --tag="kanpen-migrations"
php artisan migrate
```

This creates three tables: `subscribers`, `campaigns`, and `campaign_deliveries`.

---

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

[](#configuration)

Publish the config file:

```
php artisan vendor:publish --tag="kanpen-config"
```

This creates `config/kanpen.php`:

```
return [
    // Enable email verification (double opt-in)
    'verify' => env('KANPEN_VERIFY', false),

    // Named route to redirect to after web form submission
    'redirect_url' => 'home',

    // Verification email content
    'mail' => [
        'verify' => [
            'expiration' => 60, // minutes
            'subject'    => 'Verify Email Address',
            'greeting'   => 'Hello!',
            'content'    => ['Please click the button below to verify your email address.'],
            'action'     => 'Verify Email Address',
            'footer'     => ['If you did not sign up for our newsletter, no further action is required.'],
        ],
    ],

    // Campaign sending
    'campaigns' => [
        'enabled'    => true,
        'middleware' => ['api'],           // middleware for campaign management routes
        'from' => [
            'name'  => env('MAIL_FROM_NAME', 'Newsletter'),
            'email' => env('MAIL_FROM_ADDRESS', 'newsletter@example.com'),
        ],
        'queue'    => env('KANPEN_QUEUE', 'default'),
        'schedule' => true, // auto-register the dispatch command on the scheduler
    ],

    // Open and click tracking
    'tracking' => [
        'enabled'         => true,
        'open'            => true,
        'click'           => true,
        'allowed_domains' => [], // empty = allow all; ['example.com'] = allowlist
    ],
];
```

---

Subscriber Management
---------------------

[](#subscriber-management)

### Web Form

[](#web-form)

Add a form anywhere in your Blade views:

```

    @csrf

    Subscribe

@if (session('subscribed'))

        {{ session('subscribed') }}

@endif
```

On success the user is redirected to the route defined in `redirect_url` with a `subscribed` session flash message.

### API Endpoint

[](#api-endpoint)

A JSON endpoint is also available:

```
POST /kanpen-api/subscriber
Content-Type: application/json

{ "email": "someone@example.com" }

```

Response `201 Created`:

```
{ "created": true }
```

Duplicate emails return a `422 Unprocessable Entity` with a validation error.

### Programmatic Subscription

[](#programmatic-subscription)

Add the `HasNewsletterSubscription` trait to any Eloquent model that has an `email` attribute:

```
use Mydnic\Kanpen\Traits\HasNewsletterSubscription;

class User extends Authenticatable
{
    use HasNewsletterSubscription;
}
```

Then call the trait methods:

```
$user->subscribe();       // adds the user's email to subscribers
$user->unsubscribe();     // soft-deletes the subscriber record
$user->isSubscribed();    // returns bool
```

If `verify` is enabled in config, `subscribe()` automatically sends the verification email.

### Email Verification

[](#email-verification)

Set `KANPEN_VERIFY=true` in your `.env` (or set `'verify' => true` in config) to enable double opt-in. When enabled:

- Subscribers are saved immediately but are **not considered active** until they click the verification link.
- A verification email is sent automatically on `subscribe()` or web form submission.
- Only verified subscribers (`email_verified_at` is not null) receive campaigns.

You can customise every line of the verification email in the `mail.verify` config key.

The verification route is `GET /kanpen/verify/{id}/{hash}` — this is handled automatically.

### Unsubscribing

[](#unsubscribing)

Every subscriber gets a unique random `unsubscribe_token` generated automatically on creation. Use it to build a safe unsubscribe link — the subscriber's email address is never exposed in the URL:

```
Unsubscribe
```

This generates a URL like `/kanpen/unsubscribe/Xk9mP...` (64-char opaque token). The subscriber record is soft-deleted, and the user sees the unsubscribe confirmation page (which you can publish and customise — see [Publishing Assets](#publishing-assets)).

The token is also injected automatically into all campaign emails via the default `base.blade.php` layout, so you don't need to add it manually to campaigns.

> **Note:** For subscribers created before this version (without a token), `getUnsubscribeUrl()` generates and persists a token on the fly. The backfill migration handles bulk assignment for existing rows.

---

Campaigns
---------

[](#campaigns)

### Creating a Campaign

[](#creating-a-campaign)

Use the `Campaign` model directly:

```
use Mydnic\Kanpen\Models\Campaign;

$campaign = Campaign::create([
    'name'         => 'March Newsletter',
    'subject'      => 'What\'s new this month',
    'from_name'    => 'Acme Newsletter',     // optional, falls back to config
    'from_email'   => 'news@acme.com',       // optional, falls back to config
    'reply_to'     => 'support@acme.com',    // optional
    'content_html' => 'Hello!Here is what\'s new...',
]);
```

Campaigns are created in `draft` status and are not sent until you explicitly trigger a send.

### Sending a Campaign

[](#sending-a-campaign)

Inject or resolve the `SendCampaignAction` and call `execute()`:

```
use Mydnic\Kanpen\Actions\SendCampaignAction;
use Mydnic\Kanpen\Models\Campaign;

$campaign = Campaign::find(1);

app(SendCampaignAction::class)->execute($campaign);
```

This dispatches a queued job that:

1. Sets the campaign status to `sending`
2. Chunks through all (verified) subscribers
3. Creates a `CampaignDelivery` record with a unique tracking token per subscriber
4. Dispatches an individual queued job per subscriber that sends the email
5. Sets the status to `sent` once all jobs are dispatched

Make sure you have a queue worker running:

```
php artisan queue:work
```

### Scheduling a Campaign

[](#scheduling-a-campaign)

Set `scheduled_at` on a campaign to send it at a specific time in the future:

```
use Mydnic\Kanpen\Models\Campaign;

$campaign = Campaign::create([
    'name'         => 'March Newsletter',
    'subject'      => 'What\'s new this month',
    'content_html' => '...',
    'scheduled_at' => now()->addDays(3), // send in 3 days
]);
```

The campaign stays in `draft` status and is sent automatically when its `scheduled_at` time passes.

#### How It Works

[](#how-it-works)

The package registers the `kanpen:dispatch-scheduled` Artisan command on your application scheduler and runs it every minute:

```
kanpen:dispatch-scheduled

```

This command queries for all `draft` campaigns whose `scheduled_at` is in the past and calls `SendCampaignAction::execute()` on each of them. Internally this dispatches `SendCampaignJob` to your configured queue — the same path as an immediate send.

> **Important:** Your scheduler must be running. Add this to your server's cron if you haven't already:
>
> ```
> * * * * * cd /path-to-your-project && php artisan schedule:run >> /dev/null 2>&1
> ```

#### Opting Out of Auto-Registration

[](#opting-out-of-auto-registration)

If you prefer to schedule the command yourself (e.g. less frequently, or with a specific environment condition), set `schedule` to `false` in config and add the command manually in your `Console/Kernel.php` (Laravel 10) or `bootstrap/app.php` (Laravel 11+):

```
// config/kanpen.php
'campaigns' => [
    'schedule' => false,
],
```

```
// bootstrap/app.php (Laravel 11+)
->withSchedule(function (Schedule $schedule) {
    $schedule->command('kanpen:dispatch-scheduled')->everyFiveMinutes();
})
```

---

### Custom Blade Views

[](#custom-blade-views)

By default campaigns are rendered using the package's built-in email layout. You can point a campaign to any Blade view in your application:

```
$campaign = Campaign::create([
    'name'    => 'Special Announcement',
    'subject' => 'Big news!',
    'view'    => 'emails.special-announcement', // your own Blade view
]);
```

Your view receives these variables:

VariableTypeDescription`$campaign``Campaign`The campaign model`$send``CampaignDelivery`The per-subscriber send record`$subscriber``Subscriber`The subscriber receiving this emailExample view:

```
{{-- resources/views/emails/special-announcement.blade.php --}}

    {{ $campaign->subject }}
    Hi {{ $subscriber->email }},
    We have big news for you!
    Unsubscribe

```

Tracking (open pixel and link rewriting) is applied automatically to the rendered HTML regardless of which view is used.

### Campaign API

[](#campaign-api)

A full REST API for managing campaigns is available under `/kanpen-api/campaigns`. The middleware protecting these routes defaults to `['api']` and is configurable via `campaigns.middleware` in config.

MethodEndpointDescription`GET``/kanpen-api/campaigns`List all campaigns (paginated)`POST``/kanpen-api/campaigns`Create a new campaign`GET``/kanpen-api/campaigns/{id}`Get campaign details + stats`PUT``/kanpen-api/campaigns/{id}`Update a draft campaign`DELETE``/kanpen-api/campaigns/{id}`Soft-delete a campaign`POST``/kanpen-api/campaigns/{id}/send`Dispatch the send job`POST``/kanpen-api/campaigns/{id}/test`Send a test copy to one address**Create a campaign:**

```
curl -X POST /kanpen-api/campaigns \
  -H "Content-Type: application/json" \
  -d '{
    "name": "April Newsletter",
    "subject": "Hello from April",
    "content_html": "This month..."
  }'
```

**Get campaign stats:**

```
{
  "campaign": { "id": 1, "name": "April Newsletter", "status": "sent" },
  "stats": {
    "sent": 1200,
    "opened": 340,
    "clicked": 85,
    "open_rate": 28.33,
    "click_rate": 7.08
  }
}
```

**Send a test email:**

```
curl -X POST /kanpen-api/campaigns/1/test \
  -H "Content-Type: application/json" \
  -d '{ "email": "you@example.com" }'
```

The email is sent immediately (not queued) as an exact copy of what subscribers would receive — same subject, same content, same tracking links (though the token won't exist in the database so opens/clicks won't be recorded). Does not create any `CampaignDelivery` records or alter the campaign's status or counts. Works for campaigns in any status — useful for previewing already-sent campaigns too.

To add authentication to campaign routes, update the middleware in config:

```
'campaigns' => [
    'middleware' => ['api', 'auth:sanctum'],
],
```

---

Tracking
--------

[](#tracking)

### How It Works

[](#how-it-works-1)

When a campaign is sent, the package automatically processes every email's HTML before delivery:

1. **Open tracking** — a 1×1 transparent GIF pixel is injected just before ``:

    ```

    ```

    When a mail client loads the pixel, `opened_at` is set and `open_count` is incremented on the `CampaignDelivery` record.
2. **Click tracking** — every `` in the email is rewritten to go through a redirect proxy:

    ```
    /kanpen/tracking/click/{token}?url=

    ```

    When a subscriber clicks, the original URL is decoded, `clicked_at` is set, and the click is appended to `click_log` before the redirect.

Both tracking routes are public and do not require authentication. `mailto:` and `#anchor` links are left untouched.

### Disabling Tracking

[](#disabling-tracking)

You can disable tracking globally or individually:

```
// config/kanpen.php
'tracking' => [
    'enabled' => false, // disables all tracking
    'open'    => false, // disables open pixel only
    'click'   => false, // disables click rewriting only
],
```

### Restricting Click Tracking to Specific Domains

[](#restricting-click-tracking-to-specific-domains)

To prevent the click proxy from redirecting to arbitrary domains, set an allowlist:

```
'tracking' => [
    'allowed_domains' => ['mysite.com', 'blog.mysite.com'],
],
```

Clicks to domains not on the list return a `403` response.

### Tracking Events

[](#tracking-events)

Listen to tracking events in your `EventServiceProvider`:

```
use Mydnic\Kanpen\Events\EmailOpened;
use Mydnic\Kanpen\Events\EmailLinkClicked;

protected $listen = [
    EmailOpened::class => [
        UpdateAnalyticsDashboardListener::class,
    ],
    EmailLinkClicked::class => [
        LogClickListener::class,
    ],
];
```

Both events carry the `CampaignDelivery` model (which has the `campaign`, `subscriber`, and all tracking timestamps).

---

User Sync
---------

[](#user-sync)

You can automatically keep your application's users in sync with the subscribers table.

### HasNewsletterSubscription Trait

[](#hasnewslettersubscription-trait)

Add the `HasNewsletterSubscription` trait to your `User` model and implement the two required methods.

```
use Mydnic\Kanpen\Traits\HasNewsletterSubscription;

class User extends Authenticatable
{
    use HasNewsletterSubscription;

    /**
     * Define when this user should be a subscriber.
     * Any logic works — check a column, a role, a plan, a combination.
     */
    public function shouldBeSubscribed(): bool
    {
        return $this->subscribed_to_newsletter;
    }

    /**
     * Called automatically when the subscriber is removed from outside your app
     * (e.g. the user clicks the unsubscribe link in an email).
     * Use this to keep your own model in sync so the user isn't re-subscribed next time they save.
     */
    public function onUnsubscribed(): void
    {
        $this->updateQuietly(['subscribed_to_newsletter' => false]);
    }
}
```

**How it works:**

- When the model is saved and `shouldBeSubscribed()` returns `true` → the email is added to the subscribers table.
- When `shouldBeSubscribed()` returns `false` → the subscriber record is soft-deleted.
- When the user is hard-deleted → the subscriber record is force-deleted.
- If a previously unsubscribed user re-subscribes → the soft-deleted record is restored (no duplicate).
- When a subscriber is removed externally (unsubscribe link in email) → `onUnsubscribed()` is called on your model so your own data stays in sync.

> **Important:** Use `updateQuietly()` inside `onUnsubscribed()` to avoid triggering the `saved` event and causing a sync loop.

**Manual sync trigger:**

You can also call `syncSubscriberRecord()` directly:

```
$user->syncSubscriberRecord();
```

### Artisan Sync Command

[](#artisan-sync-command)

To sync your existing users in bulk (e.g. after adding the trait to an app that already has users), use the `kanpen:sync` command:

```
php artisan kanpen:sync "App\Models\User"
```

This calls `syncSubscriberRecord()` on every record, which in turn calls your `shouldBeSubscribed()` implementation. Records that return `true` are subscribed (or restored if previously unsubscribed), records that return `false` are soft-deleted from the subscribers table.

---

Events Reference
----------------

[](#events-reference)

All events live in the `Mydnic\Kanpen\Events` namespace.

EventFired WhenProperties`SubscriberCreated`A new subscriber is saved`$subscriber``SubscriberDeleted`A subscriber is deleted`$subscriber``SubscriberVerified`A subscriber verifies their email`$subscriber``CampaignDeliverying`A campaign's send job starts`$campaign``CampaignSent`All subscriber jobs are dispatched`$campaign``EmailOpened`A tracking pixel is loaded`$send``EmailLinkClicked`A tracked link is clicked`$send`, `$url`---

Publishing Assets
-----------------

[](#publishing-assets)

### Views

[](#views)

Publish and customise the email layout and unsubscribe page:

```
php artisan vendor:publish --tag="kanpen-views"
```

Files are copied to `resources/views/vendor/kanpen/`:

```
resources/views/vendor/kanpen/
├── mail/
│   ├── layouts/
│   │   └── base.blade.php     ← email HTML shell (header, footer, unsubscribe link)
│   └── campaign.blade.php     ← default campaign body template
└── subscriber/
    └── deleted.blade.php      ← unsubscribe confirmation page

```

Laravel's view resolution picks up your published files automatically — no config change needed.

### Vue Component

[](#vue-component)

A ready-made Vue subscription form component is available:

```
php artisan vendor:publish --tag="kanpen-vue-component"
```

Files are copied to `resources/js/components/Kanpen/`. Register and use the component in your application:

```
import SubscriberForm from './components/Kanpen/SubscriberForm.vue'

app.component('subscriber-form', SubscriberForm)
```

```

```

---

Nova Integration
----------------

[](#nova-integration)

The package ships with a ready-to-use Laravel Nova resource. Register it in your `NovaServiceProvider`:

```
use Mydnic\Kanpen\Nova\Resources\Subscriber;

public function resources(): array
{
    return [
        Subscriber::class,
    ];
}
```

The resource includes:

- An email field with uniqueness validation
- The `email_verified_at` timestamp
- A **New Subscribers** trend metric card (30 / 60 / 365 days, MTD, QTD, YTD)

---

Filament Integration
--------------------

[](#filament-integration)

The package ships with a first-class [Filament](https://filamentphp.com) plugin (v3, v4, and v5 compatible) that gives you a complete admin UI for managing subscribers and campaigns.

### Installation

[](#installation-1)

Filament must be installed and configured in your application first. See the [Filament documentation](https://filamentphp.com/docs/panels/installation) for setup instructions.

### Registering the Plugin

[](#registering-the-plugin)

Add `KanpenPlugin` to your Filament panel provider:

```
use Mydnic\Kanpen\Filament\KanpenPlugin;

public function panel(Panel $panel): Panel
{
    return $panel
        ->plugins([
            KanpenPlugin::make(),
        ]);
}
```

That's it. The plugin automatically registers all resources and widgets in your panel.

### What's Included

[](#whats-included)

#### Resources

[](#resources)

**Subscribers** (`/admin/subscribers`)

- Tabbed list: All / Active / Verified / Unverified / Unsubscribed
- Searchable by email, sortable columns
- Navigation badge showing the current total count
- Per-row actions: View, Resend Verification Email
- Bulk actions: Delete, Force Delete, Restore
- Detail view with campaign activity stats (campaigns received, opened, clicked)

**Campaigns** (`/admin/campaigns`)

- Tabbed list: All / Drafts / Sending / Sent
- Navigation badge showing the number of pending drafts
- Campaign form with rich HTML editor, custom Blade view option, from/reply-to, scheduling
- Detail view with live stats: sent count, open count, click count, open rate, click rate
- **Send Test Email** action — opens a modal with an email input; sends an exact copy of the email immediately (not queued); available on campaigns in any status so you can preview a sent campaign too
- **Send** action with confirmation modal — available only on `draft` campaigns
- Editing locked for campaigns that have already been sent

#### Widgets

[](#widgets)

**Subscribers Overview** — a stats panel showing:

- Total subscribers with a 7-day sparkline chart
- Verified subscriber count and percentage
- Total campaigns sent with pending draft count

**New Subscribers Chart** — a full-width line chart of subscriber growth with selectable time ranges (7 / 30 / 90 / 365 days).

Widgets are registered automatically and appear on your Filament dashboard.

### Customising the Plugin

[](#customising-the-plugin)

You can toggle individual resources and widgets:

```
KanpenPlugin::make()
    ->subscriberResource()          // default: true
    ->campaignResource()            // default: true
    ->subscribersOverviewWidget()   // default: true
    ->newSubscribersChartWidget()   // default: true
```

Pass `false` to disable any of them:

```
KanpenPlugin::make()
    ->newSubscribersChartWidget(false) // hide the chart widget
```

### Navigation Group

[](#navigation-group)

Both resources are placed under a **Newsletter** navigation group. To move them elsewhere, publish and extend the resource classes or override the navigation group in a service provider:

```
use Mydnic\Kanpen\Filament\Resources\SubscriberResource;
use Mydnic\Kanpen\Filament\Resources\CampaignResource;

SubscriberResource::navigationGroup('Marketing');
CampaignResource::navigationGroup('Marketing');
```

---

Upgrading
---------

[](#upgrading)

### From v1.x to v2.x

[](#from-v1x-to-v2x)

v2 is a breaking release. The following changes require attention:

**PHP and Laravel requirements**

- PHP 7.x is no longer supported. Requires **PHP 8.1+**.
- Laravel 8 and 9 are no longer supported. Requires **Laravel 10+**.

**Model namespace**

The `Subscriber` model has moved from `Mydnic\Subscribers\Subscriber` to `Mydnic\Kanpen\Models\Subscriber`.

The old class still exists as a deprecated alias, so existing code continues to work, but you should update your imports:

```
// Before
use Mydnic\Subscribers\Subscriber;

// After
use Mydnic\Kanpen\Models\Subscriber;
```

**Migrations**

Publish and run the new migrations to create the `campaigns` and `campaign_deliveries` tables:

```
php artisan vendor:publish --tag="kanpen-migrations"
php artisan migrate
```

**Events**

The three subscriber events (`SubscriberCreated`, `SubscriberDeleted`, `SubscriberVerified`) no longer implement `ShouldBroadcast`. If you were broadcasting these events, re-implement broadcasting in your own listeners.

---

License
-------

[](#license)

The MIT License (MIT). See [LICENSE](LICENSE) for details.

###  Health Score

48

—

FairBetter than 95% of packages

Maintenance66

Regular maintenance activity

Popularity32

Limited adoption so far

Community16

Small or concentrated contributor base

Maturity65

Established project with proven stability

 Bus Factor1

Top contributor holds 65.8% 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

Every ~102 days

Recently: every ~308 days

Total

21

Last Release

623d ago

Major Versions

v0.3 → v1.02019-03-08

PHP version history (3 changes)v0.1PHP ^7.1

1.7.0PHP ^7.1|^8.0

v1.9.1PHP ^7.1|8.\*

### Community

Maintainers

![](https://www.gravatar.com/avatar/bc52c3eeee29c610da76c047b3cec562c062ebb747e5e3ef097677373269b7e4?d=identicon)[mydnic](/maintainers/mydnic)

---

Top Contributors

[![mydnic](https://avatars.githubusercontent.com/u/2733767?v=4)](https://github.com/mydnic "mydnic (79 commits)")[![dependabot-preview[bot]](https://avatars.githubusercontent.com/in/2141?v=4)](https://github.com/dependabot-preview[bot] "dependabot-preview[bot] (32 commits)")[![whollaus](https://avatars.githubusercontent.com/u/4582757?v=4)](https://github.com/whollaus "whollaus (5 commits)")[![metaversedataman](https://avatars.githubusercontent.com/u/19148306?v=4)](https://github.com/metaversedataman "metaversedataman (2 commits)")[![nathanjansen](https://avatars.githubusercontent.com/u/73473323?v=4)](https://github.com/nathanjansen "nathanjansen (1 commits)")[![rabol](https://avatars.githubusercontent.com/u/1177191?v=4)](https://github.com/rabol "rabol (1 commits)")

---

Tags

laravelfeedbackcustomer

###  Code Quality

TestsPHPUnit

### Embed Badge

![Health badge](/badges/mydnic-laravel-subscribers/health.svg)

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

###  Alternatives

[livewire/volt

An elegantly crafted functional API for Laravel Livewire.

4205.3M84](/packages/livewire-volt)[gehrisandro/tailwind-merge-laravel

TailwindMerge for Laravel merges multiple Tailwind CSS classes by automatically resolving conflicts between them

341682.2k18](/packages/gehrisandro-tailwind-merge-laravel)[whitecube/laravel-timezones

Store UTC dates in the database and work with custom timezones in the application.

106106.2k](/packages/whitecube-laravel-timezones)[forxer/laravel-gravatar

A library providing easy gravatar integration in a Laravel project.

4235.6k](/packages/forxer-laravel-gravatar)[iteks/laravel-enum

A comprehensive Laravel package providing enhanced enum functionalities, including attribute handling, select array conversions, and fluent facade interactions for robust enum management in Laravel applications.

2516.7k](/packages/iteks-laravel-enum)[tomshaw/electricgrid

A feature-rich Livewire package designed for projects that require dynamic, interactive data tables.

116.6k](/packages/tomshaw-electricgrid)

PHPackages © 2026

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