Sending Mail

Sending Mail

Learn how to send mail and create templates.

This article describes how to build mail content, including using layouts and partials and then the methods used to send them. Basic Twig tags and expressions are supported in mail content. Markdown syntax is also supported, see the section on using HTML in Markdown for more details.

# Message Content

Mail messages can be sent in October CMS using either mail views or mail templates. A mail view is supplied by the application or plugin in the file system in the /views directory. Whereas a mail template is managed using the backend panel via Settings → Mail Templates.

Optionally, mail views can be registered in the plugin registration file with the registerMailTemplates method. This automatically seeds a mail template allowing them to be customized using the backend panel.

# Defining Templates in the Backend Panel

You can create mail templates stored in the database using backend panel via Settings → Mail Templates. The code given to template is a unique identifier and cannot be changed once created.

For example, if you create a template with code my-template you can send it using this PHP code:

Mail::send('my-template', $data, function($message) {
    // ...
});

If the mail template does not exist in the system, this code will attempt to find a mail view in the filesystem with the same code.

# Defining Layouts in the Backend Panel

Mail layouts can be created by selecting Settings → Mail Templates and clicking the Layouts tab. These behave just like CMS layouts, they contain the scaffold for the mail message. Mail views and templates support the use of mail layouts.

By default, October CMS comes with two default mail layouts.

Layout Code Description
Default default Used for public facing, frontend mail.
System system Used for internal, backend mail.

# Defining Views in the Filesystem

Mail views reside in the file system and the code used represents the path to the view file. For example sending mail with the code author.plugin::mail.message would use the content in following file.

├── plugins | └── author ← "author" Segment | └── myplugin ← "plugin" Segment | └── views | └── mail ← "mail" Segment | └── message.htm ← "message" Segment

The content inside a mail view file can include up to 3 sections: configuration, plain text, and HTML markup. Sections are separated with the == sequence. For example:

subject = "Your product has been added to October CMS project"
Hi {{ name }},

Good news! User {{ user }} just added your product "{{ product }}" to a project.

This message was sent using no formatting (plain text)
<p>Hi {{ name }},</p>

<p>
    <strong>Good news!</strong>
    User {{ user }} just added your product "{{ product }}" to a project.
</p>

<p>This email was sent using formatting (HTML)</p>

The plain text section is optional and a view can contain only the configuration and HTML markup sections. Markup syntax is also supported as an alternative syntax.

layout = "default"
subject = "Your product has been added to October CMS project"
Hi {{ name }},

**Good news!** User {{ user }} just added your product "{{ product }}" to a project.

# Configuration Section

The configuration section sets the mail view properties. The following configuration properties are supported.

Property Description
subject the mail message subject, required.
layout the mail layout code or view, optional. Default value is default.

# Registering Templates, Layouts & Partials

The code value in the backend panel will be the same as the mail view path. For example, author.plugin:mail.message.

Mail views can be registered as default templates created in the backend panel. Templates are registered by overriding the registerMailTemplates method of the plugin registration file. Templates can implement partials and layouts, similar to CMS themes, and these are registered with registerMailLayouts and registerMailPartials respectively.

public function registerMailTemplates()
{
    return [
        // ...Templates defined here
    ];
}

public function registerMailLayouts()
{
    return [
        // ...Layouts defined here
    ];
}

public function registerMailPartials()
{
    return [
        // ...Partials defined here
    ];
}

In the backend panel, when a generated template is saved for the first time, the customized content will be used when sending mail for the assigned code. In this context, the registered mail views can be considered default or fallback views.

# Registering a Template

The templates key in the registration array is used for registering views as mail templates. The method should return an array where the key is the template code and the value is the name of a view path. The template code is used to reference the template.

public function registerMailTemplates()
{
    return [
        'rainlab.user:activate' => 'rainlab.user::mail.activate',
        'rainlab.user:restore' => 'rainlab.user::mail.restore',
    ];
}

Sending a message uses the template code, for example.

Mail::send('rainlab.user:activate', ...);

# Registering a Layout

The registerMailLayouts method override is used to register layouts and each layout needs a unique code to identify it, along with the default view file for the contents.

public function registerMailLayouts()
{
    return [
        'marketing' => 'acme.blog::layouts.marketing',
        'notification' => 'acme.blog::layouts.notification',
    ];
}

The layout can now be referenced in templates using the code value.

layout = "marketing"
Page contents...

# Registering a Partial

Like layouts, mail partials can be registered with the registerMailPartials method override and each partial needs a unique code to identify it, along with the default view file for the contents.

public function registerMailPartials()
{
    return [
        'tracking' => 'acme.blog::partials.tracking',
        'promotion' => 'acme.blog::partials.promotion',
    ];
}

The partial can now be referenced in templates using the {% partial %} tag and code value.

{% partial 'tracking' %}

# File-based Layouts

To reference a file-based layout, you may pass the view code to the layout property. For example, this mail view references a layout of acme.blog::mail.custom-layout.

layout = "acme.blog::mail.custom-layout"
subject = "Your product has been added to October CMS project"
==
...

Using the code above, it will attempt to load the layout content from the path plugins/acme/blog/views/mail/custom-layout.htm and these contents are an example.

<html>
<body>
    <h1>HTML Contents</h1>
    <div>
        {{ content|raw }}
    </div>
</body>
</html>

The contents of file-based layouts cannot be edited in the admin panel.

# Global Variables

You may register variables that are globally available to all mail templates with the View::share method.

View::share('site_name', 'October CMS');

This code could be called inside the register or boot method of a plugin registration file. Using the above example, the variable {{ site_name }} will be available inside all mail templates.

# Sending Mail

To send a message, use the send method on the Mail facade which accepts three arguments. The first argument is a unique mail code used to locate either the mail view or mail template. The second argument is an array of data you wish to pass to the view. The third argument is a Closure callback which receives a message instance, allowing you to customize the recipients, subject, and other aspects of the mail message.

// These variables are available inside the message as Twig
$vars = ['name' => 'Joe', 'user' => 'Mary'];

Mail::send('acme.blog:message', $vars, function($message) {
    $message->to('admin@domain.tld', 'Admin Person');
    $message->subject('This is a reminder');
});

Since we are passing an array containing the name key in the example above, we could display the value within our e-mail view using the following Twig markup.

{{ name }}

You should avoid passing a message variable in your message, this variable is always passed and allows the inline embedding of attachments.

# Quick Sending

October CMS also includes an alternative method called sendTo that can simplify sending mail.

// Send to address using no name
Mail::sendTo('admin@domain.tld', 'acme.blog:message', $params);

// Send using an object's properties
Mail::sendTo($user, 'acme.blog:message', $params);

// Send to multiple addresses
Mail::sendTo(['admin@domain.tld' => 'Admin Person'], 'acme.blog:message', $params);

// Alternatively send a raw message without parameters
Mail::rawTo('admin@domain.tld', 'Hello friend');

The first argument in sendTo is used for the recipients can take different value types.

Type Description
String a single recipient address, with no name defined.
Array multiple recipients where the array key is the address and the value is the name.
Object a single recipient object, where the email property is used for the address and the name is optionally used for the name.
Collection a collection of recipient objects, as above.

The complete signature of sendTo is as follows.

Mail::sendTo($recipient, $message, $params, $callback, $options);
  • $recipient is defined as above.
  • $message is the template name or message contents for raw sending.
  • $params array of variables made available inside the template.
  • $callback gets called with one parameter, the message builder as described for the send method (optional, defaults to null). If not a callable value, works as a substitute for the next options argument.
  • $options custom sending options passed as an array (optional)

The following custom sending $options are supported.

Option Description
queue specifies whether to queue the message or send it directly, optional. Default: false.
bcc specifies whether to add recipients as Bcc or regular To addresses. Default: false.

# Building the Message

As previously mentioned, the third argument given to the send method is a Closure allowing you to specify various options on the e-mail message itself. Using this Closure you may specify other attributes of the message, such as carbon copies, blind carbon copies, etc:

Mail::send('acme.blog:welcome', $vars, function($message) {
    $message->from('us@example.tld', 'October');
    $message->to('foo@example.tld')->cc('bar@example.tld');
});

Here is a list of the available methods on the $message message builder instance.

$message->from($address, $name = null);
$message->sender($address, $name = null);
$message->to($address, $name = null);
$message->cc($address, $name = null);
$message->bcc($address, $name = null);
$message->replyTo($address, $name = null);
$message->subject($subject);
$message->priority($level);
$message->attach($pathToFile, array $options = []);

// Attach a file from a raw $data string...
$message->attachData($data, $name, array $options = []);

# Mailing Plain Text

By default, the view given to the send method is assumed to contain a mail view, where you may specify a plain text view to send in addition to the HTML view.

Mail::send('acme.blog:message', $data, $callback);

Or, if you only need to send a plain text e-mail, you may specify this using the text key in the array:

Mail::send(['text' => 'acme.blog:text'], $data, $callback);

# Mailing Parsed Raw Strings

You may use the raw method if you wish to e-mail a raw string directly. This content will be parsed by Markdown.

Mail::raw('Text to e-mail', function ($message) {
    //
});

Additionally this string will be parsed by Twig, if you wish to pass variables to this environment, use the send method instead, passing the content as the raw key.

Mail::send(['raw' => 'Text to email'], $vars, function ($message) {
    //
});

# Mailing Raw Strings

If you pass an array containing either text or html keys, this will be an explicit request to send mail. No layout or markdown parsing is used.

Mail::raw([
    'text' => 'This is plain text',
    'html' => '<strong>This is HTML</strong>'
], function ($message) {
    //
});

# Sending Attachments

To add attachments to an e-mail, use the attach method on the $message object passed to your Closure. The attach method accepts the full path to the file as its first argument:

Mail::send('acme.blog:welcome', $data, function ($message) {
    //

    $message->attach($pathToFile);
});

When attaching files to a message, you may also specify the display name and / or MIME type by passing an array as the second argument to the attach method:

$message->attach($pathToFile, ['as' => $display, 'mime' => $mime]);

# Inline Attachments

# Embedding an Image in Mail Content

Embedding inline images into your e-mails is typically cumbersome; however, there is a convenient way to attach images to your e-mails and retrieving the appropriate CID. To embed an inline image, use the embed method on the message variable within your e-mail view. Remember, the message variable is available to all of your mail views:

<body>
    Here is an image:

    <img src="{{ message.embed(pathToFile) }}">
</body>

If you are planning to use queued emails make sure that the path of the file is absolute. To achieve that you can simply use the app filter:

<body>
    Here is an image:
    {% set pathToFile = 'storage/app/media/path/to/file.jpg'|app %}
    <img src="{{ message.embed(pathToFile) }}">
</body>

# Embedding Raw Data in Mail Content

If you already have a raw data string you wish to embed into an e-mail message, you may use the embedData method on the message variable:

<body>
    Here is an image from raw data:

    <img src="{{ message.embedData(data, name) }}">
</body>

# Queueing Mail

# Queueing a Mail Message

Since sending mail messages can drastically lengthen the response time of your application, many developers choose to queue messages for background sending. This is easy using the built-in unified queue API. To queue a mail message, use the queue method on the Mail facade:

Mail::queue('acme.blog:welcome', $data, function ($message) {
    //
});

This method will automatically take care of pushing a job onto the queue to send the mail message in the background. Of course, you will need to configure your queues before using this feature.

# Delayed Message Queueing

If you wish to delay the delivery of a queued e-mail message, you may use the later method. To get started, simply pass the number of seconds by which you wish to delay the sending of the message as the first argument to the method.

Mail::later(5, 'acme.blog:welcome', $data, function ($message) {
    //
});

# Pushing to Specific Queues

If you wish to specify a specific queue on which to push the message, you may do so using the queueOn and laterOn methods:

Mail::queueOn('queue-name', 'acme.blog:welcome', $data, function ($message) {
    //
});

Mail::laterOn('queue-name', 5, 'acme.blog:welcome', $data, function ($message) {
    //
});

# See Also