Scout APM is PHP application performance monitoring designed for developers. With tracing logic that ties issues back to the line of code causing them, you can pinpoint n+1 queries, memory leaks, and other abnormalities in real time so you can knock them out and get back to building a great product. Start your free 14-day trial today and get the performance insight you need in less than 4 minutes.

Selling digital products using Laravel part 8: Mailing updates and news using Mailcoach

Original – by Freek Van der Herten – 6 minute read

We'd like to stay in touch with the people interested in our products by sending them emails when we got some news on an upcoming product, or when we are running a promo for existing products. To handle subscriptions and send out emails, we use our home-grown Laravel package Mailcoach. Let's take a look at how we use Mailcoach ourselves.

screenshot

Our digital products can be bought on spatie.be. We want each product to have it's own "face" as well, so each product has its own marketing site. Here are the ones for Front Line PHP, Media Library Pro, Mailcoach, Laravel Package Training and Laravel Beyond CRUD.

Subscribing to a list

Each of those marketing sites displays a subscription form where people can subscribe to the spatie.be email list. Here's how that looks like on the Front Line PHP site.

screenshot

When creating a new account on spatie.be there's an option to subscribe to the mailing list as well.

screenshot

The forms on the external marketing sites send a POST request to https://spatie.be/mailcoach/subscribe/. They also send a tag that will be added to the subscriber. This way, we know what content this subscriber is interested in. Here's the relevant controller in the spatie/laravel-beyond-crud.com repo.

class SubscribeToEmailListController
{
    public function __invoke(SubscribeToEmailListRequest $request)
    {
        if (! app()->environment('production')) {
            flash()->error('Subscribing is only possible in production');
        }

        $response = Http::post("https://spatie.be/mailcoach/subscribe/" .config('services.mailcoach.subscription_uuid'), [
            'email' => $request->email,
            'tags' => 'laravel-beyond-crud-waiting-list',
        ]);

        if (! $response->successful()) {
            ld()->error('Something went wrong', $response, $response);

            throw new Exception('Could not subscribe');
        }

        flash()->success('Thanks for your interest! We will keep you posted with updates on the course.');

        return back();
    }
}

Using segments

Using these tags, we can define Mailcoach segments to send emails to a specific part of our audience. Here's the segment that has all people that subscribed to the Mailcoach mailing list but has not bought Mailcoach yet.

screenshot

When v3 of Mailcoach was released, we used that segment to send a promo code to all people that were interested in Mailcoach but didn't buy it just yet.

screenshot

Send coupons automatically

We also use Mailcoach events to perform specific actions. At the moment of writing, we haven't launched our Front Line PHP course yet. To thank people for subscribing to that particular list, we send a coupon code that grants a little discount when buying one of our released products.

Here's how that's done. In EventSubscriber we've we've added a SendCoupon listener that will be executed whenever Mailcoach' SubscribedEvent is fired.

class EventServiceProvider extends ServiceProvider
{
    protected $listen = [
        // ...
        SubscribedEvent::class => [
            SendCoupon::class,
        ],
    ];
}

In SendCoupon, we check if the new subscriber does have the tag front-line-php-waiting-list. If so, we are going to send that subscriber the coupon.

Here's the code of SendCoupon:

namespace App\Listeners;

use App\Models\Subscriber;
use App\Notifications\WelcomeFrontLinePhpWaitingListNotification;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Spatie\Mailcoach\Events\SubscribedEvent;
use Spatie\Mailcoach\Models\Subscriber as MailcoachSubscriber;

class SendCoupon
{
    public function handle(SubscribedEvent $event): void
    {
        if ($event->subscriber->hasTag('front-line-php-waiting-list')) {
            $this->upcastSubscriber($event->subscriber)->notify(new WelcomeFrontLinePhpWaitingListNotification());
        }
    }

    protected function upcastSubscriber(MailcoachSubscriber $subscriber): Subscriber
    {
        $subscriber = Subscriber::findByUuid($subscriber->uuid);

        if (! $subscriber) {
            throw (new ModelNotFoundException())->setModel(Subscriber::class);
        }

        return $subscriber;
    }
}

That upcasting bit in the code above is needed because, by default, a Subscriber model of Mailcoach is not Notifiable. Our local Subscriber model extends from Mailcoach' one and is Notifiable. In Mailcoach v4, which we'll release early next year, the Subscriber will be Notifiable, so this little upcasting dance can be removed.

The WelcomeFrontLinePhpWaitingListNotification is a standard notification that sends a MailMessage.

namespace App\Notifications;

use App\Models\Subscriber;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;

class WelcomeFrontLinePhpWaitingListNotification extends Notification
{
    use Queueable;

    public function via($notifiable): array
    {
        return ['mail'];
    }

    public function toMail(Subscriber $notifiable): MailMessage
    {
        return (new MailMessage)
            ->subject("You are now subscribed to the Front Line PHP waiting list")
            ->greeting('Hi!')
            ->line("Thank you for subscribing to the Front line PHP waiting list. In the coming weeks we'll send you a couple of previews, and of course we'll notify you as soon as Front Line PHP is available.")
            ->line('We would like to offer you this coupon code, which is valid for two weeks only, that grants you a 25% discount on all products in our store:')
            ->line('WAITING-FOR-FRONT-LINE-PHP')
            ->action('Redeem the coupon on our store', route('products.index'))
            ->line("We are very excited about PHP 8 and can't wait to share our insights and knowledge with you.");
    }
}

It's pretty nice that we can use Mailcoach on our own website. I think Mailcoach is one of the better products in this category because we continuously improve it for our use case.

This series is continued in part 9: Serving ads on GitHub.

Stay up to date with all things Laravel, PHP, and JavaScript.

Follow me on Twitter. I regularly tweet out programming tips, and what I myself have learned in ongoing projects.

Every two weeks I send out a newsletter containing lots of interesting stuff for the modern PHP developer.

Expect quick tips & tricks, interesting tutorials, opinions and packages. Because I work with Laravel every day there is an emphasis on that framework.

Rest assured that I will only use your email address to send you the newsletter and will not use it for any other purposes.

Comments

Webmentions

Robin Dirksen liked on 13th October 2020
Richard Radermacher liked on 13th October 2020