Skip to content

customer.email_template.delivery_requested

Direction: server → modules. External Moleculer event name: customer.email_template.delivery_requested.

Responsibility and flow

customer.created / deposit.created / withdrawal.created / kyc.step.approved / kyc.step.rejected
  → WorkflowManager: conditions and action customer.email_template.request_delivery
  → EventBus: CustomerEmailTemplateDeliveryRecord + EV_RECORD_ADD
  → Router: explicit JSON field list
  → Moleculer: customer.email_template.delivery_requested
  → mailer: template, recipient, provider and delivery

The server does not send email and checks neither templates nor contacts. The workflow rule names the mailer template; the mailer renders and sends it. The server does not call MailerSendEmail in this flow. This is the same delegation as customer.password_reset.delivery_requested.

Workflow direction

The action customer.email_template.request_delivery is offered on customer.created, deposit.created, withdrawal.created, kyc.step.approved and kyc.step.rejected.

[
  {
    "type": "customer.email_template.request_delivery",
    "params": {"template": 12, "fallback_template": 4}
  }
]
Param Type Required Meaning
template integer Yes Mailer template id, greater than zero
fallback_template integer No Mailer template id to use when template cannot be sent, greater than zero; applied by the mailer only

Rule validation (MngValidateWorkflowRule, MngAddWorkflowRule, MngUpdateWorkflowRule):

Error When
ACTION_REQUIRED_PARAM_MISSING: customer.email_template.request_delivery.template template is missing
EMAIL_TEMPLATE_REQUIRES_VALID_TEMPLATE template is not an integer greater than zero
EMAIL_TEMPLATE_REQUIRES_VALID_FALLBACK_TEMPLATE fallback_template is present but is not an integer greater than zero

A run that executes the action fails with:

Error When
CUSTOMER_REQUIRED_FOR_ACTION: customer.email_template.request_delivery The event has no linked customer, for example a deposit on an account without customer_id
INVALID_EMAIL_TEMPLATE_DELIVERY Parameters stored in the rule fail the same check at run time

A failed action stops the rule: actions placed after it do not run, actions placed before it have already run.

Contacts are not checked: a customer without email is published as is. To skip such customers, add the condition {"field": "customer.email", "op": "exists"}; customer.email is available on all five triggers of the action.

Customer fields come from the workflow's working copy of the customer when the action runs; no extra customer lookup is made.

External output

C++ payload: CustomerEmailTemplateDeliveryRecord. Internal name: customer.email_template; accepted code: EV_RECORD_ADD. Explicit specialised external mapping: customer.email_template.delivery_requested.

The server emits a flat JSON payload. Like the password recovery event and unlike the business-event bridge, it has no event_id/event_code/occurred_at/schema_version metadata; request_id is the correlation key.

{
  "request_id": "6f1c2b9e-3d4a-4c6b-9f1e-2a7b8c9d0e1f",
  "customer_id": 140,
  "brand": "default",
  "language": "en",
  "country": "CY",
  "first_name": "John",
  "last_name": "Smith",
  "email": "[email protected]",
  "phone": "+35700000000",
  "template": 12,
  "fallback_template": 4,
  "requested_at": 1789459200
}
Field Type Meaning
request_id string UUID v4, new for every execution of the action
customer_id integer Customer identifier
brand string Customer brand
language string Customer preferred language as stored; may be empty
country string Customer country of residence
first_name string Customer first name
last_name string Customer last name
email string Customer email; may be empty
phone string Customer phone
template integer Mailer template id from the rule
fallback_template integer Fallback mailer template id; 0 when the rule sets none
requested_at integer Action execution time in Unix seconds

The payload carries no trigger, rule, trade or KYC data.

Delivery semantics

  • The event is published only when nats.enable is true. With NATS disabled the request is dropped while the workflow run succeeds.
  • Workflow success means the request was emitted, not that a module received it or sent a message. No acknowledgement, retry, replay or durable delivery is implemented.
  • Moleculer delivers the event to one node of each service that subscribed to it. Without subscribers nothing is sent and no error is raised.
  • There is no server-side deduplication: every execution produces a new request_id. Several matching rules or a repeated platform event produce several requests. Use request_id to drop repeated delivery of one request.

Mailer integration

Today the mailer sends the templates bound to its own trigger and uses the payload only to select the trigger. Wiring is configuration, not code:

  1. Create a trigger with MailerAddTrigger: event: "customer.email_template.delivery_requested" and arguments: { "match": { "template": "12" } }.
  2. Bind template 12 to that trigger (triggerId).

Create one trigger per template used in workflow rules. Without a live trigger the mailer is not subscribed and the request is lost. fallback_template is not applied in this scheme.

Planned: the mailer renders the template named in template and applies fallback_template itself. The payload already carries everything it needs. Remove the match triggers when that mode is enabled, otherwise the email is sent twice.

See Mailer: workflow email template integration.