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.enableis 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. Userequest_idto 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:
- Create a trigger with MailerAddTrigger:
event: "customer.email_template.delivery_requested"andarguments: { "match": { "template": "12" } }. - 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.