Skip to main content

Customer Emails

Saleor version required: 3.23

Saleor does not send email to customers. Customer Emails listens for store events and delivers each message through an SMTP server you connect.

It is available on Saleor Cloud from Saleor 3.23. If you are self-hosting, or still on 3.22, use the SMTP app.

Open it from Configuration → Customer emails. Content and branding are written once; which mail server sends and in which language is set per channel.

Staff emails

Staff invite and staff password reset are sent by the Admin Emails plugin. This app never sends those.

How the page is organized​

The settings page is one list of cards:

CardWhat you do there
DeliverySMTP connections, and which channel uses which one
BrandingStore name, logo, colors, help links, and the shared email layout
NotificationsTurn each email on or off, and edit the wording
TranslationsThe same emails in another language
LanguagesWhich language each channel uses
Suppressed addressesInboxes the mail server already refused
AdvancedExtra values every template can read

On a new install, a checklist at the top tracks the three things that must be true before anything can send: a connection, a sender, and at least one notification on. Branding and translations are optional.

Before anything sends​

You need three things the app cannot invent:

  • An SMTP server — Amazon SES, Mailgun, SendGrid, Mailtrap, or a local catcher. Enter host, port, encryption, and credentials. Encrypted connections (TLS and SSL) require TLS 1.3; a provider that only speaks 1.2 will fail the handshake.
  • A sender name and address on that connection. Many providers reject the message when From is not the mailbox you authenticated as.
  • For account emails, a storefront page that consumes the token URL Saleor puts in the message. The app only delivers. See Manage account as a customer.

After install, the recommended emails are already on. Nothing is delivered until a connection exists.

Delivery​

Add a connection: a name you will recognize, host, port, encryption, credentials, and the sender customers see.

  • Port 587 with TLS (STARTTLS), or 465 with SSL (implicit TLS), is what most providers expect. The form flags a mismatch before you save.
  • Test connection on the card proves the server answers. It does not send a customer email.

Each channel sends through exactly one connection, so a customer never receives the same email twice.

The first connection is the store default: every channel you have not assigned elsewhere sends through it. Assign a channel only when it should use a different connection. With two or more connections, Make default is in that connection's menu; it asks before channels that currently use the store default start sending through the new one. If the default mark is missing and you have exactly one active connection, that one is used.

Writing emails​

Templates are MJML. The app compiles them to HTML when it sends. You edit MJML in the Dashboard; you do not paste HTML or a design from another tool.

Dynamic values use Handlebars. Examples you will see in the shipped templates:

{{order.number}}
{{customer.firstName}}
{{branding.siteName}}
{{#each order.lines}}
{{this.productName}}
{{/each}}

The Sample data tab is only for the preview and for test emails. A real send uses the order or account that triggered it. The editor suggests fields from that tab. A helper the app does not ship fails the preview and the send.

Shared layout​

Edit layout on the Branding card. The layout is the MJML document every notification sits in: the <mjml> wrapper, styles, header, and footer.

Exactly one {{{content}}} marks where the notification body goes. Triple braces are required so the body is inserted as markup, not escaped text. You cannot save without that placeholder, or with more than one.

Preview the layout wrapped around any notification. Until you save a change, emails use the layout that ships with the app.

Notifications​

Open a row to edit the subject and body. The shipped body is an MJML fragment — sections and columns, not a full document. The layout wraps it.

Saving a change makes that text yours. Later app updates no longer change it. Reset to default (or Delete translation on a language that is not the store default) goes back to the shipped copy.

Send test email from the editor uses the version on screen, including unsaved edits, filled with sample data. Subjects start with [Test]. It does not depend on whether customers receive that notification. From Notifications you can also send every enabled email to one inbox; that path uses the saved templates, still with sample data.

Branding​

Store-wide values, not markup. Change them once and every template picks them up. Templates read:

FieldHandlebars
Store name{{branding.siteName}}
Logo{{branding.logoUrl}}
Shop URL{{branding.shopUrl}}
Accent color{{branding.accentColor}}
Help centre{{branding.helpUrl}}
Support address{{branding.supportEmail}}
Postal address{{branding.addressLine}}

Empty store name and address fall back to Configuration → Store → Store details.

Use a PNG or JPEG on a URL that stays reachable. SVG and signed or expiring links look fine in the Dashboard preview and often fail in the inbox. The app warns; it does not block save.

The Order page URL field is a link pattern, not an email template. Put {{id}} or {{number}} in that field (or {{order.id}} / {{order.number}}) so the View order details button can point at a real order, for example https://example.com/order/{{id}} or /account/orders/{{number}}. A path is joined to Shop URL. The button is left out when the field is empty or the link cannot be built.

{{customer.firstName}} is filled from the account or the order address, so a greeting works for guests too.

Custom variables​

Under Advanced, add key-value pairs available in every template as {{customVariables.yourKey}}. Use this for a storefront URL or a support address you would otherwise repeat in sixteen templates.

Which emails exist​

On after install: Order created, Order confirmed, Order fulfilled, Order cancelled, Order refunded, and the six account emails.

These stay off because they stack on that set, or they fire from a staff action:

  • Order fully paid can fire for the same purchase as Order created and Order confirmed.
  • Shipment created fires in the same moment as Order fulfilled when the order ships in one go.
  • Invoice sent, Order fulfillment updated, and Gift card sent are staff-triggered.
EmailSends whenStorefront
Order createdAn order is placed—
Order confirmedThe order is confirmed—
Order fully paidThe order is fully paid—
Order cancelledThe order is cancelled—
Order refundedA refund is issued—
Invoice sentStaff sends an invoice—
Shipment createdStaff creates a shipment and leaves notify customer on—
Order fulfilledThe order is fully fulfilled—
Order fulfillment updatedA tracking number is updated—
Customer account confirmationA shopper registers, and Configuration → Site settings requires email confirmation. If that setting is off, nothing is sent.Confirm account
Customer account password setupStaff creates a customer with a password-setup linkSet password
Customer account password reset requestA customer requests a password resetReset password
Customer account change email requestA customer requests an email changeChange email
Customer account change email confirmationThe email change completed—
Customer account delete requestA customer requests account deletionDelete account
Gift card sentA gift card is sent to a customer—

Account emails and the storefront​

Saleor builds the link from the mutation's redirectUrl. The app puts that link in the email. If the storefront route is wrong, the message arrives and the customer cannot finish.

Manage account as a customer covers confirmation, password reset, email change, and account deletion. Staff-created accounts that need a first password are in Customer management.

Language​

Saleor channels have a country, not a language. This app is where you wire the three together:

  1. Languages — connect each channel to a language (and turn on any others you want to write).
  2. Notifications — the emails themselves: Order created, Order confirmed, password reset, and the rest. Turn each one on or off, and edit the wording.
  3. Translations — the same emails in another language. Open a cell to edit Order confirmed in German, for example. The editor can show the store default beside it.

When something happens, the app picks a language, then the wording. It uses the language on the order or account. Turn Always on for a channel if everyone buying there should get that channel's language instead. If the order or account has no language, the channel language, then the store default.

A saved template in that language wins. If there is none, the base language can stand in — Brazilian Portuguese can use Portuguese. After that, a saved store-default template. If nothing is saved, the app sends the copy it ships in the customer's language when it has one: German, English, Spanish, Finnish, French, Japanese, Korean, Polish, Portuguese, and Simplified Chinese. A language it does not ship uses English, even when the store default is something else. They get mail, not an empty inbox.

Once you edit the store-default wording, later sends use that edit for every language you have not translated. The Translations card marks those languages as not translated so you can see the gap.

Suppressed addresses​

When the mail server refuses a recipient as unknown — SMTP 550, 551, or 553, or the address on the server's rejected list — the app stores that address and skips later emails to it. The skip is a success for Saleor: nothing to retry.

A Dashboard app problem points at Suppressed addresses in settings. Removing a visible address is how you undo a false positive; the next genuine refusal puts it back. Settings shows the 50 most recently refused and how many there are in total.

A 554 (bad message or sender refused) does not add the customer. A store outage does not block a valid send.

Saleor Cloud preview mail​

warning

Send previews through Saleor's mail server runs only when no connection matches the channel — no assignment, no store default, and not a single active connection. Customers receive nothing: each email goes to the organization owner instead, marked as a preview, with the intended recipient in the subject.

It does not override a connection you already added. Channels that use the store default still send through that connection. On a new Cloud install the toggle is on, so you see mail before you add SMTP. Turn it off and, with no connection, nothing sends. Production needs your own connection.

If you used the SMTP app​

This is a different app (saleor.app.customer-emails). Installing it does not upgrade or replace saleor.app.smtp.

  • Do not leave both sending. The old app can still send more than one email for the same event when multiple configurations match a channel.
  • Settings do not move over from the Dashboard. Set this app up as new, or ask Saleor if you are on Cloud and need an import.
  • Each channel now sends through exactly one connection. The old "all channels except" filter is gone.
  • A customized template imported from the SMTP app arrives as a complete MJML document. It does not use the shared layout. Reset to default if you want the header and footer back.

If nothing arrives​

  1. A connection exists and is assigned to the channel — or it is the store default, or the only one. On Cloud, preview mail to the organization owner is not a substitute for that connection.
  2. That connection has a sender.
  3. The notification is on.
  4. The old SMTP app is not the one still sending, and both are not on.
  5. For account confirmation: Site settings still requires confirmation.
  6. The address is not on Suppressed addresses. Remove it there if a refusal was a false positive.
  7. The provider rejected the message. Permanent replies (unknown mailbox, rejected credentials) stop immediately. A 554 is the message or the sender, not the customer. Transient failures still retry.

Saleor webhook retries do not send a second copy of the same event to the same address.