On this page:

Upgrading to v8

V8 brings a completely redesigned Mailcoach, as such this release is light on breaking changes in functionality but can be a time consuming upgrade if you’ve customised any views.

Updating your composer.json

  1. Update the requirement of spatie/laravel-mailcoach to ^8.0

  2. Run a composer update

composer update spatie/laravel-mailcoach -W

Clear your icon & view cache

php artisan icon:clear
php artisan view:clear

Add a scheduled task to calculate transactional mail statistics


View changes

Most of the views have changed considerably. If you have published the Mailcoach views and have made changes, the most straightforward way to update them is to run:

php artisan vendor:publish --tag=mailcoach-views --force

And re-apply any changes you made previously to the views.

Config changes

The default TextAreaEditorComponent has been removed, the new defaults in the config file are the following:

'content_editor' => \Spatie\Mailcoach\Livewire\Editor\TextAreaEditorComponent::class,
'content_editor' => \Spatie\Mailcoach\Domain\Editor\Markdown\Editor::class,

'template_editor' => \Spatie\Mailcoach\Livewire\Editor\TextAreaEditorComponent::class,
'template_editor' => \Spatie\Mailcoach\Domain\Editor\Codemirror\Editor::class,


Only 2 columns have been added in the new release, you can add them using this migration:

return new class extends Migration
    public function up()
        Schema::table('mailcoach_transactional_mail_log_items', function (Blueprint $table) {

            $table->index(['mail_name', 'created_at'], 'mail_name_index');

        Schema::table('mailcoach_tags', function (Blueprint $table) {

Sendinblue renamed to Brevo

Any references that still existed have been renamed from Sendinblue to Brevo. Make sure any references in your own codebase are updated as well.

Upgrading the standalone spatie/Mailcoach skeleton

If you’ve created a Mailcoach Self-Hosted project using our starter skeleton. Be sure to upgrade the provided components as well, check out the full diff for all the required changes: https://github.com/spatie/Mailcoach/commit/67dce12b850762c771239904b6eb14edb7380fa4

Upgrading to v7

Updating your composer.json

  1. If your composer.json contains any of the additional Mailcoach packages, you can safely remove them. They are now included in the core laravel-mailcoach package.
  2. Update the requirement of spatie/laravel-mailcoach to ^7.0
  3. laravel/sanctum is no longer a requirement for Mailcoach. If you are not using this inside your application, make sure config/sanctum.php is removed.

Packages safe to remove

    "require": {
        "spatie/laravel-mailcoach-editor": "^2.0",
        "spatie/laravel-mailcoach-mailgun-feedback": "^5.0",
        "spatie/laravel-mailcoach-mailgun-setup": "^1.0",
        "spatie/laravel-mailcoach-markdown-editor": "^2.0",
        "spatie/laravel-mailcoach-monaco": "^3.0",
        "spatie/laravel-mailcoach-postmark-feedback": "^5.0",
        "spatie/laravel-mailcoach-postmark-setup": "^1.0",
        "spatie/laravel-mailcoach-sendgrid-feedback": "^5.0",
        "spatie/laravel-mailcoach-sendgrid-setup": "^1.0",
        "spatie/laravel-mailcoach-sendinblue-feedback": "^1.0",
        "spatie/laravel-mailcoach-sendinblue-setup": "^1.0",
        "spatie/laravel-mailcoach-ses-feedback": "^5.0",
        "spatie/laravel-mailcoach-ses-setup": "^1.0",
        "spatie/laravel-mailcoach-unlayer": "^3.0",       

Clear your view cache

php artisan view:clear

Encryption has been removed

Mailcoach no longer supports encrypting the data of subscribers. This caused too many issues with Mailcoach features.

Be sure to decrypt before upgrading to v8, you can do this with the steps below:

  1. Disable encryption by setting mailcoach.encryption.enabled to false
  2. Create & run the command below to decrypt all subscribers

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use ParagonIE\CipherSweet\BlindIndex;
use ParagonIE\CipherSweet\CipherSweet as CipherSweetEngine;
use ParagonIE\CipherSweet\EncryptedRow;
use Spatie\Mailcoach\Domain\Audience\Encryption\Transformation\EmailFirstPart;
use Spatie\Mailcoach\Domain\Audience\Encryption\Transformation\EmailSecondPart;
use Spatie\Mailcoach\Domain\Audience\Encryption\Transformation\Lowercase;
use Spatie\Mailcoach\Domain\Audience\Models\Subscriber;

class DecryptSubscribersCommand extends Command
    protected $signature = 'app:decrypt-subscribers';

    protected $description = 'Decrypts all subscribers';

    public function handle(): void
        $encryptionKey = config('mailcoach.encryption.key');

        if (Str::startsWith($encryptionKey, $prefix = 'base64:')) {
            $encryptionKey = base64_decode(Str::after($encryptionKey, $prefix));

        config()->set('ciphersweet.providers.string.key', $encryptionKey);

        $row = new EncryptedRow(
            (new Subscriber())->getTable(),


        $row->addBlindIndex('email', new BlindIndex('email_first_part', [new EmailFirstPart()]));
        $row->addBlindIndex('email', new BlindIndex('email_second_part', [new EmailSecondPart()]));

        $row->addBlindIndex('first_name', new BlindIndex('first_name', [new Lowercase()]));
        $row->addBlindIndex('last_name', new BlindIndex('last_name', [new Lowercase()]));

        Subscriber::each(function (Subscriber $subscriber) use ($row) {
                    ->setPermitEmpty(config('ciphersweet.permit_empty', false))
                    ->decryptRow($subscriber->getAttributes()), true

                ->where('id', $subscriber->id)
                    'first_name' => $subscriber->first_name,
                    'last_name' => $subscriber->last_name,
                    'email' => $subscriber->email,
  1. Change the email, first_name and last_name columns to strings
Schema::table('mailcoach_subscribers', function (Blueprint $table): void {
  1. Drop the blind_indexes table

Removed User model

Mailcoach no longer provides a User model of its own. You can now extend the default Laravel model instead and implement our MailcoachUser interface:

- use \Spatie\Mailcoach\Domain\Settings\Models\User as MailcoachUserModel;
+ use Illuminate\Foundation\Auth\User as Authenticatable;
+ use Spatie\Mailcoach\Domain\Settings\Models\MailcoachUser;

- class User extends MailcoachUserModel
+ class User extends Authenticatable implements MailcoachUser

+ public function canViewMailcoach(): bool
+ {
+     return true;
+ }

Inside the canViewMailcoach() method you can add additional checks if needed for your use-case.

// config/auth.php

'providers' => [
    'users' => [
        'driver' => 'eloquent',
-        'model' => \Spatie\Mailcoach\Domain\Settings\Models\User::class,
+        'model' => \App\User::class,

Config changes

There have been numerous config changes, you can view the full diff here: https://github.com/spatie/laravel-mailcoach/pull/1360/files

The easiest way to update this is to run

php artisan vendor:publish --tag=mailcoach-config --force

And re-apply any changes you made previously to the config.

Laravel Sanctum is no longer included

In an effort to be more flexible and letting the package users choose which authentication systems to use. Mailcoach no longer configures Laravel Sanctum by default.

If you’d like to continue using sanctum, you can install and configure it according to the docs.

View changes

Some views have changed considerably, take a look at the PR diff here: https://github.com/spatie/laravel-mailcoach/pull/1360/files

The easiest way to update this is to run

php artisan vendor:publish --tag=mailcoach-views --force

And re-apply any changes you made previously to the views.

Livewire namespace has moved

If you have extended any Mailcoach Livewire components, their namespace has been moved from





Like with previous upgrades, we’ve supplied a migration that will update all the necessary columns and move over any existing data.

Unlike previous upgrades, we suggest doing this upgrade in 3 steps:

Make sure to take a backup before running any migrations or commands.

1. Adding new columns

You’ll find the Add Columns Migration here.

Copy and paste this migration into your project to run it.
You might need to tweak this migration to fit your needs.

2. Migrating data

We made a console command to upgrade your data to the new structure.
If you installed mailcoach as a package in an existing application, you might need to tweak this command to fit your needs.

You’ll find the Add Columns Command here.

Copy and paste this command into your project to run it.
You might need to tweak this migration to fit your needs.

We suggest running this in steps in either a migration or console command depending on what you’re comfortable with.

3. Remove old columns and data

Be sure to verify that the data migration ran successfully and Mailcoach v8 is working correctly before running this migration.

You’ll find the Cleanup Migration here.

Copy and paste this migration into your project to run it.
You might need to tweak this migration to fit your needs.

Upgrading to v6

This version adds numerous new features and a completely new look to Mailcoach.

Some notable features:

  • Completely new design with improved UX
  • Add & manage multiple mailers with different providers with automatic setup
  • Show a website archive of your email list’s campaigns
  • A full-featured template system
  • A new & improved Markdown editor
  • Send outgoing webhooks
  • Improved list insights & charts
  • A new “Manage preferences” screen where subscribers can manage the (public) tags attached to them
  • A command palette
  • Automations can be configured to run more than once for a subscriber
  • The ability to override, replace and extend every page of Mailcoach

Updating your composer.json

  • If your composer.json contains spatie/mailcoach-ui, you can remove this as it’s now included within the core laravel-mailcoach package.
  • Update the requirement of spatie/laravel-mailcoach to ^6.0
  • Mailcoach now requires PHP 8.1, so make sure to update that requirement as well
"require": {
-     "php": "^8.0",
+     "php": "^8.1",
    "fruitcake/laravel-cors": "^2.0.5",
    "guzzlehttp/guzzle": "^7.2",
    "laravel/framework": "^9.0",
    "laravel/horizon": "^5.9",
    "laravel/tinker": "^2.7",
-     "spatie/laravel-mailcoach": "^5.0",
+     "spatie/laravel-mailcoach": "^6.0",
-     "spatie/mailcoach-ui": "^5.0"

Composer scripts

  • The composer hook command has been renamed, make sure to edit this in your scripts section if it is present, usually only in a standalone installation:
  • The necessary migrations will now be published by the publish command
"scripts": {
    "post-autoload-dump": [
        "@php artisan package:discover --ansi"
    "post-root-package-install": [
        "@php -r \"file_exists('.env') || copy('.env.example', '.env');\""
    "post-create-project-cmd": [
        "@php artisan key:generate --ansi",
-         "@php artisan vendor:publish --tag mailcoach-migrations",
-         "@php artisan vendor:publish --tag mailcoach-ui-migrations",
        "@php artisan mailcoach:prepare-git-ignore",
-         "@php artisan mailcoach:execute-composer-hook"
+         "@php artisan mailcoach:publish"
    "post-update-cmd": [
-         "@php artisan mailcoach:execute-composer-hook",
+         "@php artisan mailcoach:publish",
        "@php artisan vendor:publish --tag=laravel-assets --ansi --force"

Remove the mailcoach-ui routes

Mailcoach UI required separate routes to be registered, in the standalone version these are registered inside your RouteServiceProvider, you can remove these and replace them by the default Mailcoach route macro:

public function boot()

-     Route::mailcoachUi('/');
+     Route::mailcoach('/');


After this, you can run a composer update

Update your Schedule

There have been a few changes to the scheduled commands, make sure your Mailcoach commands in your app/Console/Kernel.php file look like this:

protected function schedule(Schedule $schedule)



Methods like runInBackground() and withoutOverlapping() are no longer necessary as we dispatch unique jobs inside the command instead.

Update the login route

Mailcoach has now prefixed its authentication routes, if you don’t have any login route of your own, add the following to your app/Exceptions/Handler.php:

protected function unauthenticated($request, AuthenticationException $exception)
    return $this->shouldReturnJson($request, $exception)
        ? response()->json(['message' => $exception->getMessage()], 401)
        : redirect()->guest($exception->redirectTo() ?? route('mailcoach.login'));

Configuration updates

  • Delete the config/mailcoach-ui.php file if present in your installation, be sure to port over any changes to the config/mailcoach.php config file.

A full diff of the config file can be found here

We recommend running php artisan vendor:publish --tag=mailcoach-config --force which will override your old configuration file with the new one. Using a git diff you can then re-apply any changes you previously made to your configuration file.

Notable changes to the config file are documented below:


Throttling config is no longer set inside the Mailcoach configuration file, these settings can be controlled for each mailer

Welcome mails

Any configuration relating to welcome mails have been removed, you can now create a welcome automation instead.


All views now use Livewire components which you can override in the config to add your own functionality if necessary.


A schedule queue was added to Mailcoach, make sure your horizon config contains it:

'mailcoach-general' => [
    'connection' => 'mailcoach-redis',
-     'queue' => ['general', 'mailcoach', 'mailcoach-feedback', 'send-mail', 'send-automation-mail'],
+     'queue' => ['general', 'mailcoach-schedule', 'mailcoach', 'mailcoach-feedback', 'send-mail', 'send-automation-mail'],
    'balance' => 'auto',
    'processes' => 10,
    'tries' => 2,
    'timeout' => 60 * 60,

If you’re using simple balancing, make sure the schedule queue is defined early as that determines priority.

User model

If you use your own User model, make sure to replace the one in config/mailcoach.php with your own:

'models' => [
-     'user' => \Spatie\Mailcoach\Domain\Settings\Models\User::class,
+     'user' => \App\Models\User::class,

The standalone starter project defined the Auth user model as \Spatie\MailcoachUi\Models\User, replace this with the new User model, or your own model in config/auth.php.

'users' => [
    'driver' => 'eloquent',
-     'model' => Spatie\MailcoachUi\Models\User::class,
+     'model' => \Spatie\Mailcoach\Domain\Settings\Models\User::class,


Delete the resources/views/vendor/mailcoach folder if you did not have any changes made to the views.

Otherwise, we recommend deleting the folder anyway and re-publishing to port over any of your changes.

Run php artisan view:clear to delete any compiled views.

Migration changes

There have been a few additions and changes to the Mailcoach tables, you can use the migration below to update your database:

Some notable changes:

  • All models now have a UUID
  • Custom confirmation mails now use transactional mails instead of raw html

Make sure you have doctrine/dbal installed in your app for rename migrations to work.

composer require doctrine/dbal

You’ll find the upgrade to v6 migration here

Depending on how much data you have this could take a long time. It might be a good idea to split this up into separate migrations.

If you’re already using Laravel MediaLibrary make sure that the media table in your project has the same fields as the media migration included with Mailcoach.

Open & Click tracking

The Campaign, AutomationMail and TransactionalMail no longer have the ability to enable/disable open & click tracking.

This is because this is a setting at the provider level that Mailcoach has no direct control over. You could disable tracking in Mailcoach but still have tracking links & pixels present because the settings was enabled at your provider.

When setting up mailers through the new mailer UI, Mailcoach will make the necessary API calls to enable/disable tracking for that provider.

Transactional models renamed

The Spatie\Mailcoach\Domain\TransactionalMail\Models\TransactionalMail model has been renamed to Spatie\Mailcoach\Domain\TransactionalMail\Models\TransactionalMailLogItem

The Spatie\Mailcoach\Domain\TransactionalMail\Models\TransactionalMailTemplate model has been renamed to Spatie\Mailcoach\Domain\TransactionalMail\Models\TransactionalMail

Make sure to rename these in the correct order if you reference these inside your application.


We’ve reworked how Mailcoach translations work, if you had published them make sure to republish the translations.

If you referenced Mailcoach translations somewhere in your app, make sure to replace it by the new helper, the mailcoach - prefix is no longer necessary:

- {{ __('mailcoach - Some translation string') }}
+ {{ __mc('Some translation string') }}

- {{ trans_choice('mailcoach - One|More', 2) }}
+ {{ __mc_choice('One|More', 2) }}


All API resources & endpoints now use uuids instead of ids for references to models. Update your integrations with the API if necessary.

Unlayer users

This version of Mailcoach uses an newer version of Unlayer. Your old templates might not be compatible. To make Unlayer templates compatible, you might try the code mentioned in this issue. Also take look at this issue

If you still reference Route::mailcoachUnlayer() somewhere in project, you should remove it.