Skip to content
Saleor
Esc
↑↓navigate↵open⌘Jpreview
On this page

Customer Emails

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.

How the page is organized

The settings page is one list of cards:

Card What you do there
Delivery SMTP connections, and which channel uses which one
Branding Store name, logo, colors, help links, and the shared email layout
Notifications Turn each email on or off, and edit the wording
Translations The same emails in another language
Languages Which language each channel uses
Suppressed addresses Inboxes the mail server already refused
Advanced Extra 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:

Field Handlebars
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.
Email Sends when Storefront
Order created An order is placed —
Order confirmed The order is confirmed —
Order fully paid The order is fully paid —
Order cancelled The order is cancelled —
Order refunded A refund is issued —
Invoice sent Staff sends an invoice —
Shipment created Staff creates a shipment and leaves notify customer on —
Order fulfilled The order is fully fulfilled —
Order fulfillment updated A tracking number is updated —
Customer account confirmation A shopper registers, and Configuration → Site settings requires email confirmation. If that setting is off, nothing is sent. Confirm account
Customer account password setup Staff creates a customer with a password-setup link Set password
Customer account password reset request A customer requests a password reset Reset password
Customer account change email request A customer requests an email change Change email
Customer account change email confirmation The email change completed —
Customer account delete request A customer requests account deletion Delete account
Gift card sent A 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

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.

Last updated on September 8, 2026

Was this page helpful?