Abandoned cart emails module

Module id: abandoned_cart. Dependencies: checkout.

A shopper who leaves items in their cart gets one email some hours later, listing what is in it, with a button that puts the cart back.

The module is off on every website until it is switched on in the Modules tab. The sidebar item (Abandoned carts, Commerce section, next to Review requests) opens its settings.

Who gets a reminder

Only shoppers whose address the shop already has:

  • Customers who are logged in. Their cart is kept with their account, so the reminder goes to the account's address, in the account's language.
  • Guests who went to the payment page and did not pay. Their order was cancelled (payment failed, cancelled or expired) and the cart is still there. The reminder goes to the address on that order, in the order's language.

A guest who leaves before pressing the order button cannot be reached: the email field is not saved until the order is placed. That is deliberate.

Not reminded:

  • A cart that was ordered from after its last change: paid, shipped, or still awaiting payment (a bank transfer, for instance).
  • An emptied cart.
  • Shoppers who unsubscribed from cart reminders on this website.
  • Shoppers reminded recently: someone who got a reminder within Remind the same shopper again after days does not get another for a new cart. 0 reminds about every cart.
  • A deleted or disabled customer account.

When

Every 15 minutes the platform looks for carts whose last activity is at least Hours after the cart was left ago. The last activity is the later of the last change to the cart and the moment a guest went to pay.

Each abandonment gets at most one reminder. A shopper who comes back, changes the cart and leaves again has abandoned it again, and can get a new reminder, subject to the repeat rule above.

A cart more than 48 hours past due is let go. That stops switching the module on from emailing every cart on record, and it also means a missed run, or a website that fixes its sender address, still reminds this morning's shoppers.

What operators set

Setting Default What it does
Hours after the cart was left 3 1 to 72.
Remind the same shopper again after 7 days 0 to 90. 0 = remind about every cart.
Email text (per language) built-in text Subject and opening paragraph. Blank = the built-in text in that language. %shop% and %name% (first name) are filled in.

Nothing is sent while the website has no sender address. The settings screen says so in red.

A discount code to win the shopper back goes in the opening text ("Use code WELCOMEBACK for 10% off"). Create the code under Discounts first; the mail does not apply it, the shopper types it at checkout.

The button opens /cart/recover/{token}. It adds what the reminded cart holds to the cart of whoever opens it, and shows the cart:

  • It works on another device than the one the cart was filled on.
  • Prices are today's, stock and minimum quantities are checked again, and a product unpublished or restricted since is left out. The shopper is told when something could not come back.
  • A product already in the cart is topped up to the reminded quantity, never added on top, so opening the link twice does not double anything.

The mail itself shows no prices, for the same reason: the cart may no longer say what yesterday's mail would.

The law

Treat a cart reminder as a marketing email. The safe route under Dutch and EU rules: tell shoppers near the email field at checkout, and in the privacy statement, that they may get a reminder about an unfinished order, and let every mail carry a working opt-out (it does, see below). Whether that is enough for a given shop is the shop's call; the module does not ask for consent itself.

Unsubscribe

Every reminder carries an unsubscribe link and a one-click List-Unsubscribe header (RFC 8058). Unsubscribing stops cart reminders from this website to that address, nothing else: order mails, review requests and the newsletter are not affected. The link keeps working after the module is switched off.

Where to see what was sent

The settings screen shows how many reminders went out in the last 30 days, and in how many of those the cart link was opened. A link checker in the shopper's mail (some company mail scans every link) counts as an opening.

A reminder is not part of an order, so it is not in any order's Emails tab. If a send fails (the mail server was down) it is recorded as failed and not retried: one reminder too few is better than two.

Public routes

Route Method What
/cart/recover/{token} GET The button in the email: puts the cart back, then shows /cart. 404 while the cart module is off.
/cart/reminders/unsubscribe/{token} GET, POST Opt-out link from the email; POST is the one-click unsubscribe from mail providers.

Overridable templates

Template What
abandoned_cart/email/abandoned_cart.html.twig (+ .txt.twig) The email. Inputs: website, subject, locale, customer_name, message (the shop's own text or null), items (list of name, quantity), cart_url, unsubscribe_url.
abandoned_cart/unsubscribe.html.twig The page after unsubscribing. Inputs: website, result (done or invalid).

Scheduled job

cms-cron-abandoned-cart-remind in cms-k8s runs app:schedule:dispatch abandoned-cart:remind every 15 minutes. It only queues the work; cms-worker sends the mails on the analytics queue.