Skip to content

Bulk Emails

Mass emails

Domain model

Emails

Notifiables

<?php

namespace JohnIt\Bc\Contacts\Domain\Models;

use Illuminate\Notifications\Notifiable;
use JohnIt\Bc\Core\Domain\Contracts\NotifiableContract;

class Contact extends Model implements NotifiableContract
{
    use Notifiable;

    /**
     * Route notifications for the mail channel.
     *
     * @param  \Illuminate\Notifications\Notification  $notification
     * @return array|string
     */
    public function routeNotificationForMail($notification)
    {
        // Return primary email address of contact
        return $this->emails()->primary()->first()?->email;
    }
}

Generating emails and sending mass emails

Sending batch e-mails.

Sending batch e-mails is implemented as a 2 step procedure where first step is done by developer and second by end user. It can also be sent without user intervention by developer.

Initiating batch e-mails for user to complete

Initiating batch e-mail sending is very simple. Lets say you want to send email to first 10 people in database:

use JohnIt\Bc\Core\Domain\Models\StoredIterator;
use Domain\Correspondence\Models\BatchDistribution;
use Domain\Person\Models\Person;

$batch = BatchDistribution::forIterator(
    StoredIterator::fromQueryBuilder(
        Person::with('emails')->has('emails')->limit(10) //do not include ->get(). Query builder itself is needed here, not results.
    ),
);

return Redirect::to(route('bulk-mails.edit', ['bulk_mail' => $batch->id]));

BatchDistribution is the key object here. You can pass it an array of related models to be saved and be viewable later by user. For example if you are sending mass e-mails because of some event include that event object as a second parameter in array:

use JohnIt\Bc\Core\Domain\Models\StoredIterator;
use Domain\Correspondence\Models\BatchDistribution;
use Domain\Person\Models\Person;

$batch = BatchDistribution::forIterator(
    StoredIterator::fromQueryBuilder(
        Person::with('emails')->has('emails')->limit(10) //do not include ->get(). Query builder itself is needed here, not results.
    ),
    [$event, $someOtherModelToBeLinkedToThisBatchCampaign]
);

return Redirect::to(route('bulk-mails.edit', ['bulk_mail' => $batch->id]));
User interface will also generate placeholders for included related models so that user can for example use event name as a variable in the body of e-mail. If you do not want to use list of automatically generated placeholders you can implement \Support\ProvidesPlaceholders interface and provide your own list of placeholders.

The model object (in this case Person) must contain an attribute called full_name and an attribute of type array called batch_emails. JohnIt\Bc\Core\Domain\Models\HasEmails trait already contains implementation for emails attribute.

How to initiate batch e-mails from a list in DataTable.
  1. On server side add this code inside controller (adjust according to your needs):
use JohnIt\Bc\Core\Domain\Models\StoredIterator;
use Domain\Correspondence\Models\BatchDistribution;
use Domain\Person\Models\Person;
use JohnIt\Bc\Ui\Presentation\DataTables\Factory;

public function tabulate(): DataTable
{
    $this->authorize('viewAny', Person::class);

    return Factory::make(Person::query())
        ...
        ->addActionFromObject('sendEmail', $this)
        ->setRowId('id');
}

public function sendEmail($table): RedirectResponse
{
    $this->authorize('create', BatchDistribution::class);

    //here pay attention to calling of getFilteredQuery to get current query from DataTable.
    $query = $table->getFilteredQuery()->with('emails')->has('emails');
    if ($query->count() == 0) {
        flash(trans('bc-core-presentation::bulk-mail.flash.list_empty'))->error();

        return Redirect::back();
    } else {
        $batch = BatchDistribution::forIterator(
            StoredIterator::fromQueryBuilder($query),
        );

        return Redirect::to(route('bulk-mails.edit', ['bulk_mail' => $batch->id]));
    }
}

On client side add this code:

<x-coreui::datatable
    :dataset="[
        'buttons' => [
            [
                'extend' => 'collection',
                'text' => '<i class=' . chr(34) . 'cil-clear-all' . chr(34) . '></i> ' . trans('app.batch_actions'),
                'autoClose' => true,
                'className' => 'btn-info',
                'buttons' => [
                    Auth::user()->can('create', \JohnIt\Bc\Core\Domain\Models\BulkMail::class) ? [
                        'extend' => 'openAction',
                        'method' => 'POST',
                        'name' => 'sendEmail',
                        'text' => '<i class=' . chr(34) . 'cil-mail' . chr(34) . '></i> '. trans('app.send_email'),
                        'confirm' => trans('bc-core-presentation::bulk-mail.send_init_confirmation'),
                    ] : []
                ]
            ],
        ],
        'ajax' => ['url' => route('person.tabulate')],
        'order' => [1, 'asc'],
    ]"
>
    ...
</x-coreui::datatable>

Thats all.

Initiating and dispatching batch e-mails completely from code

To send batch e-mails with free text:

use JohnIt\Bc\Core\Domain\Models\StoredIterator;
use Domain\Correspondence\Models\BatchDistribution;
use Domain\Person\Models\Person;
use Domain\Correspondence\Contracts\StartBatchDistributionActionInterface;

$batch = BatchDistribution::forIterator(
    StoredIterator::fromQueryBuilder(
        Person::with('emails')->has('emails')->limit(10) //do not include ->get(). Query builder itself is needed here, not results.
    ),
    [$someRelatedModel]
);
$action = app(StartBatchDistributionActionInterface::class);
$action(
    $batch->id, 
    'Title for user reference',
    'Subject',
    'Body',
    [], //can provide document ids here
    [request('file')]
);

To send batch e-mails with your own Mailable:

use JohnIt\Bc\Core\Domain\Models\StoredIterator;
use Domain\Correspondence\Models\BatchDistribution;
use Domain\Person\Models\Person;

$batch = BatchDistribution::forIterator(
    StoredIterator::fromQueryBuilder(
        Person::with('emails')->has('emails')->limit(10) //do not include ->get(). Query builder itself is needed here, not results.
    )
);
//provided closure will be called for each instance of $model retrieved from database.
$batch->dispatch(function ($batch, $model) {
    return new YourOwnMailable($model, [], []);
});
Please, note that YourOwnMailable class must NOT implement ShouldQueue interface as it is already being sent on background thread.