Emails
Once you’ve defined a suite of order statuses, you can configure Commerce to send emails as orders move between them.
Commerce’s email system is completely flexible—you choose when emails are sent, who they’re sent to, and what they contain. This can be disorienting at first, because there is no built-in notion of a receipt or shipping confirmation!
Before setting up emails for Craft Commerce, ensure that your Craft installation has a properly configured mail adapter.
Commerce emails are sent via the queue. To ensure prompt delivery, consider setting up a dedicated queue runner!
Let’s look at an example For example, you might create an email called “Customer Order Confirmation” which emails a completed order summary to the customer. This would be linked to the default order status since we want it to trigger when the cart’s completed and becomes an order.
Another email could be “Admin Order Notification,” also attached to the default order status. Instead of being sent to the customer, however, it could go to the store owner’s email address and include stock or packing information.
The store manager can also send any email manually from an order’s edit page—whether that’s to re-send an email from a previous status change, or to send an email that is otherwise not connected to order statuses.
# Creating an Email
Emails are managed per-store. To create a new email, navigate to
- Commerce
- System Settings
- Emails
Emails have the following configuration settings. Unless otherwise noted, textual settings are treated as object templates, and are provided two special variables:
order
— the Order object (opens new window) that triggered the email;orderHistory
— the OrderHistory object (opens new window) created as the order changed status, ornull
if the email was triggered manually;
This allows you to customize the behavior of an email, without
Each email can only be triggered once by a status change. If you need to send an email to multiple recipients, you can provide them as a comma-separated list in the To field.
# Name
A label for the email, visible when managing it in the control panel. This is not displayed to customers.
# Email Subject
The “Subject” line of the email.
Order #{{ order.id }} received.
# Recipient
The “To” address or addresses for this email.
If “Send to the customer” is selected, the email will be sent to the order’s customer in the language (locale) that customer used placing the order. This affects the use of the |t
filter in other email fields that support Twig.
If “Send to custom recipient” is selected, a comma-separated list of email addresses can be entered.
Like the Email Subject, this field is an object template. Two special variables are available:
order
— the Order object (opens new window) that triggered the email;orderHistory
— the OrderHistory object (opens new window) created as the order changed status, ornull
if the email was triggered manually;
order
is the cart or order relevant to the notification. To replicate the “Send to the customer” behavior, you might provide this:
{{ order.email }}
You may use a custom field in the order field layout that contains an email address, if the customer can designate
# Reply-To Address
The Reply-To address for this email.
This field takes plain text as well as Twig values. Two special variables are available:
order
is a populated Order object (opens new window).orderHistory
is a populated OrderHistory object (opens new window).
# BCC’d Recipient
The BCC addresses for this email. Most likely, you would BCC the store owner on order confirmation.
Separate multiple addresses with a comma (,
).
This field takes plain text as well as Twig values. Two special variables are available:
order
is a populated Order object (opens new window).orderHistory
is a populated OrderHistory object (opens new window).
# CC’d Recipient
The CC addresses for this email. Separate multiple addresses with a comma (,
).
This field takes plain text as well as Twig values. Two special variables are available:
order
is a populated Order object (opens new window).orderHistory
is a populated OrderHistory object (opens new window).
# HTML Email Template Path
The path to an HTML template in your site’s templates/
folder.
This field takes plain text as well as Twig values. Two special variables are available:
order
is a populated Order object (opens new window).orderHistory
is a populated OrderHistory object (opens new window).
This allows you to have full design flexibility.
# Plain Text Email Template Path
The path to a plain text template in your site’s templates/
folder.
This works the same way as the “HTML Email Template Path”.
# PDF Attachment
Choose a PDF that will be attached to this email.
# Email Language
Under most circumstances, emails are sent in the language of the site the order was placed in. Commerce captures this at checkout, and it cannot be changed after the order is completed. As a result, emails triggered by orders from a single store can be rendered in different languages, if that store is attached to multiple sites.
Set up static message translations if you need to localize parts of your emails.
# Selecting an Email
To use an email you’ve configured, visit
- Commerce
- System Settings
- Order Status
Choose the email by name in the Status Emails field. You can select as many emails as you’d like.
Once you choose Save, the designated emails will be sent when an order is assigned that status.
# Suppressing Emails
There may be cases where you don’t want an order status change to send an email. When updating an order’s status (from its edit screen, or an element index), you can select Suppress emails to prevent Commerce from sending any emails attached to the new status:
This setting is retained only for the duration of the request, so subsequent status changes must also set this flag.
If you wish to conditionally suppress automatically-triggered emails, Commerce emits a cancelable event any time it is preparing to send one. Set the event object’s $isValid
property to false
to prevent the email from being sent:
use craft\commerce\events\OrderStatusEmailsEvent;
use craft\commerce\services\OrderStatuses;
use yii\base\Event;
Event::on(
OrderStatuses::class,
OrderStatuses::EVENT_ORDER_STATUS_CHANGE_EMAILS,
function (OrderStatusEmailsEvent $event) {
$newStatus = $event->orderHistory->getNewStatus();
// Prevent shipping notifications going out for orders without a shippable item:
if ($newStatus->handle === 'shipped' && !$order->hasShippableItems()) {
$event->isValid = false;
}
}
);
This will suppress all emails associated with the new status. To prevent individual emails from being sent (regardless of how they were triggered), or to modify some aspect of the email before it is sent, you can use the craft\commerce\services\Emails::EVENT_BEFORE_SEND_MAIL (opens new window) event:
use craft\commerce\events\MailEvent;
use craft\commerce\services\Emails;
use craft\helpers\StringHelper;
use yii\base\Event;
Event::on(
Emails::class,
Emails::EVENT_BEFORE_SEND_MAIL,
function (MailEvent $event) {
$order = $event->order;
$email = $event->craftEmail;
// Add store administrator to any email sent regarding unpaid orders:
if ($order->getIsUnpaid()) {
$email->setBcc('help@pixelandtonic.com');
}
}
);
# Troubleshooting
It’s a good idea to always test your status email templates before relying on them in production.
Once you’ve configured a template, the quickest way to test it is by navigating to Commerce → System Settings → Emails and choosing Preview next to the relevant email. This will open a new tab/window to display the template rendered using a random completed order.
You can add &number=ORDER_NUMBER
to the preview URL to use a specific number. Replace ORDER_NUMBER
with the order number you’d like to preview.
If your template is rendering successfully but messages are failing to send, you’ll want to check these things in order:
- Make sure Craft’s queue is running.
If therunQueueAutomatically
setting istrue
you may want to establish a more reliable queue worker. - Make sure any dynamic settings are parsed properly.
Some email settings support dynamic Twig values, where parsing errors can cause sending to fail:- Email Subject
- Reply To
- Recipient
- BCC’d Recipient
- CC’d Recipient
- HTML Email Template Path
- Plain Text Email Template Path
- Make sure the HTML and Plain Text template paths exist and parse properly.
Syntax issues, undeclared variables, or missing information may prevent templates from rendering. - Make sure included PDFs render properly.
If you’re including a PDF, it could have its own rendering issues that cause sending to fail. Be sure to preview the relevant PDF separately and ensure it’s working as expected. - Avoid cart and session references.
Emails are sent by queue processes that don’t have access to cookies or sessions the cart depends on. References tocraft.commerce.carts.cart
orcraft.commerce.customers.customer
, for example, will result in session-related errors.
Commerce adds email jobs to the queue with high priority for drivers that support it. This helps ensure outgoing messages don’t get stuck behind slow, long-running tasks.
When an email fails to send in response to a status change, its queue job will be marked as failed and include an appropriate message. Once you fix the cause of the sending failure, you can retry sending the email from the queue via Utilities → Queue Manager.
If a plugin suppresses an email (by listening to EVENT_BEFORE_SEND_MAIL
and assigning $event->isValid
to false
), queue jobs will complete normally.