Skip to main content

Mailing

Qore includes mailing, mail templates and more by default.

You are not required to use this when sending e-mails.

Mail templates use Twig and may contain pre-defined variables.

Getting started

In order to use mailing, make sure you publish the latest Qore resources:

php artisan vendor:publish --tag=qore

And run the migrations.

Skeleton ships with the following menu items in MakesMenu:

// Add group: "Mailing"
$this->addTabGroup(1, [
'icon' => 'forward_to_inbox',
'title' => __('Mailing'),
'items' => [
$this->resourceToMenuItem(resource(MailTemplate::class)),
$this->resourceToMenuItem(resource(MailMessage::class)),
$this->resourceToMenuItem(resource(MailFooter::class)),
$this->resourceToMenuItem(resource(TwigTemplate::class)),
[
'route' => '/settings/mailing',
'title' => __('Settings'),
'permissions' => [
'mail management'
]
],
]
]);

Mail templates

Every e-mail message can be sent from a mail template.

Variable lists

You can select a variable list which will determine which resource and which fields (variables) will be availbable in the (Twig) content.

You can define a variable list, for example when sending e-mails to employees:

class EmployeeVariableList extends VariableList
{
// Will be shown in the dropdown (must be unique)
public function name(): string
{
return 'Employee';
}

// The variables that will be shown for the user on the right side
public function variables(): array
{
return [
__('Employee') => $this->resourceToTags(resource('employees'), 'employee'),
'Custom' => [
'somevariable'
]
];
}

// The resource for this variable list
public function resource(): QoreResource
{
return resource('employees');
}

// Here the variables are mapped to actual values
public function map(int|null $modelId, array $args = []): array
{
$resource = resource('employees');
$employee = $resource->retrieve($modelId);

return [
'employee' => $this->resourceToVariables($resource, $employee)
'somevariable' => 'somevalue'
];
}

// Optional: group for the dropdown
public function group(): string
{
return 'Modules';
}

// Optional: to retrieve the e-mail address for the model
public function getEmailAddress(Model $model): string
{
return $model->{$this->emailColumn()};
}
}

You can then register your VariableList in a Service Provider:

app(VariableListRegistrar::class)->register(new EmployeeVariableList());

Layouts

E-mail messages can be sent with a wrapping layout (optional). You can define your own layout in recources/views/mailing/layouts.

Layouts are automatically detected for the dropdown.

Masking sensitive data

Sometimes you need to mask variables that contain sensitive data.

You can do this in the content of your mail templates:

Your new password is: [confidential]{{ password }}[/confidential].

Sending e-mails

You can send e-mails from your mail templates, or manually:

info

Mails will respect the configured QUEUE_CONNECTION

QoreMail::send(
'Forgot password', // Name of the mail template
$this->id, // List of ids or single id
);

// Or if you want to customize more:

QoreMail::send(
'Forgot password', // Name of the mail template
[1, 2], // List of ids or single id
[
'token' => $token
], // Array of arguments
Carbon::now()->addHours(2) // Plan the e-mail for another time
[
'some' => 'data'
], // Additional metadata that should be saved on the message table as json
$this->model, // Instigator (optional related model which triggered/related to the mail)
function (MailMessage $message) { // Optional closure to modify the mail message just before sending
$message->content = 'Edited mail content'
$message->save();
}
);
warning

Mail templates can be defined per tenant, so when you need to use mail templates outside of the authentication layer, you need to identify with a tenant first.

Fore example, if you want to send the Forgot password mail for a user, add this to your User model:

public function sendPasswordResetNotification($token)
{
if (!tenant()) {
if ($this->tenant_id) {
tenancy()->initialize($this->tenant_id);
} else {
tenancy()->initialize(tenants()->first());
}

boot_extensions();
}

QoreMail::send('Forgot password', $this->id, ['token' => $token]);
}

Manually dispatching the job

Sometimes you need more control when sending e-mails. Here is an example:

$mailList = resource('mail_lists')->retrieve($mailListId);
$to = $mailList->getFilteredModels()->pluck('id')->toArray();
$mailTemplate = MailTemplate::find($mailTemplateId);

(new BulkMessageMailer(
$mailTemplate, // Mail template
$to, // Receiver
['form_id' => $this->model->id], // Data for the mail list
null, // Planned at date
[], // Metadata to be stored in the table as json
$this->model // Instigator (optional related model which triggered/related to the mail),
function (MailMessage $message) { // Optional closure to modify the mail message just before sending
$message->content = 'Edited mail content'
$message->save();
}
))->send();

Sending a Notification

You may have a Laravel Notification that you want to send via email. Instead of using the default Laravel 'mail' channel you should use QoreMailChannel.

Steps to send a notification through QoreMail:

  1. Create a notification class

    • The QoreMailChannel should be added in the via function
    • The class should implement the SendableWithQoreMail interface which will make you implement a function called toQoreMail
  2. Update the $notifiable model

    When you send a notification, you will call Laravels internal function, Notification::send($model, ...), the $model should have the Notifiable trait included, and have a function called routeNotificationForQoreMail defined.

    QoreMail expects a model so we can just return $this inside that function, for the User model we can do this:

    class User extends QoreUser
    {
    public function routeNotificationForQoreMail($driver, $notification = null)
    {
    return $this;
    }
    }

The toQoreMail function expects you to return a QoreMailMessage:

// set the template name !mandatory
QoreMailMessage::make()
->template('Test sjabloon');

// set the args that will be sent to variable list (to the map() function)
QoreMailMessage::make()
->template('Test sjabloon')
->args([
'user' => [
'name' => $this->user->name,
'email' => $this->user->email
]
]);

// set the schedule (planned_at from QoreMail)
QoreMailMessage::make()
->template('Test sjabloon')
->planAt(Carbon::now()->addHours(2));

Example below:

<?php

namespace App\Notifications;

use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
use Qore\System\Mailing\Notifications\QoreMailChannel;
use Qore\System\Mailing\Notifications\QoreMailMessage;
use Qore\System\Mailing\Notifications\SendableWithQoreMail;

class NotificationExample extends Notification implements SendableWithQoreMail
{
use Queueable;

public function via($notifiable): array
{
return [QoreMailChannel::class];
}

public function toArray($notifiable)
{
return [
//
];
}

public function toQoreMail(mixed $notifiable): array
{
return QoreMailMessage::make()
->template('Sjabloon name');
}
}
tip

You can modify Laravel's internal stub files to change the notification from using default mail channel to the QoreMailChannel.

Commands and crons

E-mails can be planned to be sent in the future instead of directly.

This however means that a cron should take care of this:

$schedule->command('qore:mail')->everyMinute();