Skip to content

Powered by Grav

Coming soon — KahunaCart is in final testing. Join the list and be first to know. Join the list

Emails

This page lists the emails KahunaCart sends to customers and shows you how to enable, customize and test them. It is for the store administrator.

Before you begin

  • Install and configure the Email plugin. Without it every email job throws Email plugin is not available and lands in the failed bucket.
  • Put Grav's scheduler in cron. Every email is queued rather than sent inline, and bin/plugin kahunacart work does the sending. See Troubleshooting.

The emails KahunaCart sends

Every email is queued as a job, so nothing a customer or an administrator does waits on a mail server.

Email Job type Sent when Templates
Order confirmation order.confirmation_email An order completes order-confirmation.*
Payment received order.payment_received_email An order awaiting payment becomes paid payment-received.*
Shipped order.shipped_email An order is marked as shipped shipped.*
Refund order.refund_email A provider confirms a refund refund.*
Abandoned cart cart.abandoned_sweep A cart sits untouched past cart.abandoned_hours abandoned-cart.*
Set password customer.set_password_email A customer opts into an account at checkout, or a merchant sends an invitation set-password.*

Abandoned-cart reminders are off by default. The set-password email is sent only when store accounts are enabled.

The order confirmation is also BCC'd to the store when emails.store_copy_to is set. The other emails are not copied to the store.

When the payment-received email is sent

An instant-capture provider completes an order that is already paid, so no payment-received email is sent. The confirmation has already said everything this email would.

The email covers the offline case: a bank transfer completes the order with the payment pending, a merchant marks it paid days later, and this email tells the customer the money arrived. A redirect provider whose webhook lands after the customer leaves produces one too.

When the refund email is sent

The refund email is queued when the provider confirms a refund, never when one is submitted. A refund still awaiting confirmation sends nothing. See Orders → Refunds that are not over when you click.

The amount comes from the job payload rather than from the order, because an order can carry several refunds.

Tracking numbers in the shipped email

KahunaCart does not record a tracking number, so the shipped email does not carry one. Fulfillment is a single flag on the whole order — see Orders → Fulfillment status.

Note

A store that has tracking numbers can add them in a template override.

Each email sends once

Each email is queued at a transition that is already guarded against repeating: CheckoutService::complete() for the confirmation, CheckoutService::markPaid() for the payment-received email, a fulfill endpoint that refuses an order which is not unfulfilled, a transaction ledger whose markSuccess() returns false for a row that already succeeded, and a stamp written into the cart's data_json after an abandoned-cart send. A redelivered webhook or a double-clicked admin button queues nothing the second time. A job that throws is retried with exponential backoff, so a failed send is tried again and a successful one is never repeated.

Templates

Each email is a pair of Twig templates, HTML and plain text. Both are sent, and the recipient's mail client picks one.

TXT
templates/emails/order-confirmation.html.twig    order-confirmation.txt.twig
templates/emails/payment-received.html.twig      payment-received.txt.twig
templates/emails/shipped.html.twig               shipped.txt.twig
templates/emails/refund.html.twig                refund.txt.twig
templates/emails/abandoned-cart.html.twig        abandoned-cart.txt.twig
templates/emails/set-password.html.twig          set-password.txt.twig

On a multilanguage site each order email renders in the language the order was placed in: subject line, both templates and the money formatting. The set-password email is the exception, because a customer record carries no language. See Multilanguage.

Variables in the order emails

Variable What it is
order The order row, including number, hash, currency and the status columns
items Its line items, each with title, qty, unit_price_minor, is_digital
adjustments Its adjustments — discounts, shipping, tax
total The order total, already formatted
site_name site.title, or empty

The refund email adds three more: amount (this refund, formatted), amount_minor, and refunded_total (everything confirmed on the order so far).

Variables in the set-password email

Variable What it is
customer_name The customer's name, or empty
customer_email The address the account is keyed to, which is also their username
set_password_path The site-relative reset URL. Prefix it with base_url_absolute
expires Unix timestamp at which the link stops working
site_name site.title, or empty

Override an email template

A theme overrides an email template by name.

  1. Create a templates/emails/ directory in your theme.
  2. Copy the template you want to change out of user/plugins/kahunacart/templates/emails/ into it.
  3. Edit the copy.
  4. Repeat for the other half of the pair so the HTML and plain-text versions match.

The next send uses your version.

Turn on abandoned-cart reminders

  1. Set cart.abandoned_enabled to true.
  2. Set cart.abandoned_hours to the idle time a cart must reach. The default is 24.
  3. Optionally set emails.abandoned_subject to your own subject line. Leave it blank to use the translated default.

Reminders go out on the next worker tick. Each cart is mailed at most once.

Test that emails are sending

  1. Place a test order on the storefront.
  2. Run the worker by hand, then check the queue counts.
BASH
bin/plugin kahunacart work      # run the queue by hand
bin/plugin kahunacart status    # pending / failed / completed job counts

A failed job keeps its last_error. The most common cause of missing mail is a scheduler that was never installed in cron.

Translate the email strings

Every string in every template goes through |t. Subjects go through the language system too, with the order number as a positional argument so a translation can move it inside the sentence.

YAML
EMAIL_SHIPPED_SUBJECT: 'Order #%s is on its way'

Keys live under PLUGIN_KAHUNACART. in languages/en.yaml. The abandoned-cart subject is the one that can also be set in config, with emails.abandoned_subject.

Configuration reference

Key Default Effect
emails.store_copy_to empty BCC address for order confirmations
emails.abandoned_subject empty Overrides the translated abandoned-cart subject
cart.abandoned_enabled false Turns abandoned-cart reminders on
cart.abandoned_hours 24 How long a cart must sit idle before it earns a reminder

The From address comes from the Email plugin's own from and from_name settings.