29 · Tenant email for operations

How each business configures outbound mail, how the platform falls back, and which operational events send customer email (receipts, invoices, refunds, store credit).

Multi-tenant SMTP / SendGrid / SES Platform SMTP fallback email_log audit

Transport resolution (per send)

flowchart TD
  SEND[sendEmail / OpsEmail] --> T1{Tenant email_settings
provider != none + active?} T1 -->|yes| USE1[Business SMTP / SendGrid / SES] T1 -->|no| T2{TicketSettings
emailEnabled + SMTP?} T2 -->|yes| USE2[Ticket SMTP] T2 -->|no| T3{Platform env
SMTP_HOST / SMTP_URL?} T3 -->|yes| USE3[Platform SMTP — shared rail] T3 -->|no| FAIL[skipped_no_provider + log] USE1 --> LOG[(email_log tenant main)] USE2 --> LOG USE3 --> LOG

Live platform already has SMTP env; tenants without their own settings still send via platform with GPE From unless they configure branding in email_settings.

HTTP API — /api/email

MethodPathPurpose
GET/statuscanSend, source, provider, from
GET/settingsRead business email config (+ status)
POST/settingsUpsert SMTP/SendGrid/SES for this org
POST/testSend branded test message
POST/sendOps template: receipt, invoice, refund, store_credit, void, custom
POST/invoice/:idEmail Core Invoice as receipt/invoice
GET/logsRecent email_log rows for this org

Operational templates (opsEmail.service.js)

TypeWhen to use
receipt / invoiceCustomer sale document with line items + totals
refundRefund confirmation
store_creditSC- code after refund-to-credit
voidVoid notice
testSettings verification
customAd-hoc HTML/text

Product wiring

  • Core refundPOST /api/core-invoicing/refund-invoice returns emailNotify (default on; pass notifyCustomer:false to skip; optional notifyEmail)
  • Receipts/api/receipts/:invoiceId/email and /send use tenant email service first, platform mailer fallback
  • TicketsticketNotification.service already uses email.service
  • Invoice emailPOST /api/email/invoice/:id loads Core invoice + line items

What each business should configure

  1. Business Hub / Email settings → provider SMTP (or SendGrid/SES)
  2. From name + From email (aligned with domain SPF/DKIM at their DNS)
  3. Optional reply-to for customer replies
  4. Send test to owner inbox
  5. If left empty: platform SMTP still delivers (shared From) — fine for demos, not ideal for brand/reputation
Platform env SMTP_HOST, SMTP_USER, SMTP_PASS, MAIL_FROM power fallback. Never put tenant passwords in platform env; store per-tenant in email_settings.

Files

  • backend/services/email.service.js — transport resolution + email_log
  • backend/services/opsEmail.service.js — templates + invoice/refund helpers
  • backend/services/mailer.js — legacy platform-only helper (still used as last resort)
  • backend/routes/email.routes.js — HTTP API
  • backend/routes/receipts.routes.js · coreInvoicing.routes.js — call sites
  • Related: DocHub 23 tax/receipts/notifications