Appearance
Template
An SMS template is a single <rc-sms> element. It exists in two equivalent representations — XML and JSON — that convert to each other without loss. Either can be written by hand (or generated by an LLM), or assembled in code using the sms builder namespace.
Every template must include an unsubscribe footer — see Unsubscription. The examples below include it.
XML
The body of <rc-sms> is a plain SMS RFM string. Placeholders use the ::placeholder{…} directive; the content model documents the syntax for links and all placeholder types. The ::unsubscribe directive expands to the required footer — see Unsubscription.
xml
<rc-sms>Your order has shipped!
Account: ::placeholder{type="Subscriber" original="[Subscriber:email]" name="Email" value="email"}
::unsubscribe</rc-sms>xmlToSms() parses this format into an SmsDocument; safeXmlToSms() is the non-throwing variant. Both validate structure — see Validation.
JSON
The JSON representation is the canonical format the Rule API accepts and returns. The content field is an SmsContentJson — a flat sequence of nodes; see Content for the full content model.
json
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"tagName": "rc-sms",
"content": {
"type": "sms",
"content": [
{ "type": "message", "text": "Your order has shipped!\nAccount: " },
{
"type": "placeholder",
"attrs": {
"type": "Subscriber",
"name": "Email",
"original": "[Subscriber:email]",
"value": "email"
}
},
{
"type": "message",
"text": "[Subscriber:unsubscribe_text]",
"attrs": { "is-unsubscribe": true }
},
{
"type": "placeholder",
"attrs": {
"type": "Link",
"original": "[Link:Unsubscribe]",
"name": "Unsubscribe",
"value": null,
"is-unsubscribe": true
}
}
]
}
}Validate a JSON document with validateSmsDocument() (throws on failure) or safeValidateSmsDocument() (returns a result object) — see Validation.
Programmatic
Build the same document with createSmsDocument() and the sms builder namespace. createUnsubscribeNodes() produces the required footer — see Unsubscription.
typescript
import { sms, createSmsDocument } from '@rule/rcml';
const doc = createSmsDocument({
content: sms.createContent({
nodes: [
sms.createMessageNode({ text: 'Your order has shipped!\nAccount: ' }),
sms.createSubscriberPlaceholder({ field: 'email' }),
...sms.createUnsubscribeNodes(),
],
}),
});createSmsDocument also accepts an SMS RFM string directly as content — convenient when content is authored as a plain string or generated by an LLM:
typescript
const doc = createSmsDocument({
content:
'Your order has shipped!\n' +
'Account: ::placeholder{type="Subscriber" original="[Subscriber:email]" name="Email" value="email"}\n' +
'::unsubscribe',
});createSmsDocument validates the document and throws SmsDocumentBuildError on failure. Use safeValidateSmsDocument for the non-throwing variant — see Validation.
Related
- Content —
SmsContentJsoncontent model and node types - Unsubscription — required unsubscribe footer
rc-sms— element and type reference- Building programmatically — full API walkthrough
- Validation — error types and validation functions