Table of Contents

Email

"They never got the email" splits into three different problems with three different answers. Find out which one you have before doing anything else.

The three failure points

flowchart LR
    A["Work queued"] --> B["Handler runs"]
    B --> C["Send accepted<br/>and logged"]
    C --> D["Delivered to<br/>the inbox"]

    A -.->|"never drained"| X1["Async work"]
    B -.->|"handler failed"| X1
    C -.->|"no log row"| X2["Never sent"]
    D -.->|"log row exists"| X3["Delivery problem"]

    style A fill:#e8f4f9,stroke:#00415a,stroke-width:2px,color:#002230
    style B fill:#e8f4f9,stroke:#00415a,stroke-width:2px,color:#002230
    style C fill:#f5f3ff,stroke:#7c3aed,stroke-width:2px,color:#2e1065
    style D fill:#eef2ff,stroke:#4f46e5,stroke-width:2px,color:#1e1b4b
    style X1 fill:#fff1f2,stroke:#be123c,color:#4c0519
    style X2 fill:#fff1f2,stroke:#be123c,color:#4c0519
    style X3 fill:#fff1f2,stroke:#be123c,color:#4c0519

Start with the email log. Whether a row exists tells you which half of the problem you are in, and that is the only question worth answering first.

Log row Meaning Next step
No row Commerce never sent it It is queued, retrying, or the handler is failing → Async work
Row exists Commerce sent it and the provider accepted it The problem is delivery, not the platform — see below

What the email log records

Searchable from the back office, with a detail view per entry.

Field What it gives you
Template key Which email this was — order acknowledgement, invitation, and so on
Related entity type and id What it was about, for example an order id. This is how you find the email for a given order
Recipient The address it actually went to. Check this against the address the customer expects
Subject As rendered
Sent at When it was accepted by the provider
Provider message id The provider's own identifier — quote this when escalating to the mail provider

The related entity id is the field to search on. Working back from an order number to its acknowledgement is the common case.

When a row exists but nothing arrived

Commerce's part succeeded. The provider accepted the message and gave back an identifier, and that is the end of what this platform can see.

Delivery after that point is outside Commerce entirely, and the usual causes are:

  • The recipient address is wrong — check the log's recipient against what the customer expects, and against the customer record
  • The message was filtered as spam or quarantined
  • The recipient domain rejected or deferred it

Take the provider message id to the mail provider. Commerce holds no delivery status, no bounce record and no open tracking. If a bounce came back, it came back to the provider, not here.

Note

There is no resend button. The log is a record of what was sent, not a console for sending. If a message genuinely needs to go again, the business event behind it has to be raised again.

Checking what an email would look like

The template screens can render a template against sample data without sending anything. Two uses worth knowing:

  • Confirming a fix. After a template change, preview it rather than placing a test order.
  • Answering "what did it say?". The log stores the subject but not the rendered body. Previewing the template shows the shape of what was sent, though not that specific recipient's data.

Templates and their layouts are stored in the database and editable live — a wording change is a back-office edit, not a deployment.

Where email is sent from

Delivery goes through Azure Communication Services, authenticated by the application's managed identity. There is no SMTP credential to rotate and no third-party mail account.

Practically: if sending is failing for every recipient rather than one, suspect the platform identity or the service itself rather than the templates — and the handler's error in the queue will say so.