Mailing

Layouts, templates, providers, rules, and a log — everything for transactional email.

The email-manager extension

All outgoing email goes through the email-manager extension. No other extension speaks raw SMTP — they fire a core.email.send call, the manager picks it up, applies the layout/template, hands it to the active provider, and logs the result.

Manage at /admin/email. Five surfaces inside: Layouts, Templates, Providers, Rules, Logs.

Email layouts

Manage at /admin/email/layouts. A layout is the outer wrapper — brand header, footer, signature, unsubscribe link. Templates pick a layout to wrap themselves in.

What you set

  • Slug
  • Name
  • HTML template — Go html/template, must include {{ .body }} where the message body slots in
  • Plain-text template — separate template for the plain-text part of multipart messages
  • Default — mark one layout as the default; new templates inherit it

Email templates

Manage at /admin/email/templates. A template is a single message — welcome email, password reset, order confirmation. Each template has:

  • Slug — referenced by rules and forms
  • Subject — with {{variable}} interpolation
  • Body — rich editor, same interpolation
  • Layout — picker; defaults to the layout marked default
  • Variables — declared schema (custom-field-style), so the admin's preview can render with sample values

Preview

The Preview button renders the template against the variables schema's sample values, exactly like the recipient would see it.

Providers

Pluggable. Today:

  • smtp-provider — gRPC plugin, talks to any SMTP server (Postmark, SES SMTP relay, your own MTA)
  • resend-provider — Tengo extension, ~20 lines, talks to Resend.com

Activate exactly one as the active provider. To switch, deactivate the current one and activate another. Manage at /admin/email/providers; provider-specific settings (API key, SMTP host/port/auth) are exposed by the provider extension.

Roadmap

SES native, Postmark native, Mailgun, SendGrid — all welcome as community extensions. The provider contract is a single event subscription.

Rules

Manage at /admin/email/rules. A rule says when X event fires, send template Y to recipients Z. Each rule has:

  • Trigger event — picker pulling from the live event bus catalog: node.created, node.updated, node.deleted, user.registered, user.password_reset_requested, form.submitted, media.uploaded, plus any extension-emitted event
  • Conditions — same operators as forms; e.g. node.node_type = "page"
  • Recipients — static, from-event-payload ({{user.email}}), or from-role-subscription (every user subscribed to this event in this role)
  • Template — picker
  • Throttle — optional, e.g. "max 1 per user per hour"
  • Active — toggle
TIP
Combine rules with role-level email subscriptions to wire up automatic notifications: "any role with the node:created:page subscription gets the page-published email".

Logs

Browse at /admin/email/logs. Every send recorded with:

  • Timestamp, provider, status (queued, sent, failed, bounced, complained)
  • To / From / Subject / template / rule
  • Provider response (raw)
  • Retry count and last-retry timestamp
  • Rendered body (HTML + text) for forensic review

Click any row to inspect; failed deliveries can be resent with one click.