Custom email templates

What you can change

For the emails listed below you can supply your own body and, optionally, your own subject.
The frame around every email stays ours: the logo band, the legal footer and the French section are
added automatically and cannot be replaced. Text messages (SMS, WhatsApp) are not affected.

Send us one .tpl file per email (maximum 256 KB) and, if you want one, a subject line. We load it
for your account, check it, send you a preview, and switch it on. If anything in your template ever
fails to render, the standard email is sent instead (with the standard subject), so a mistake in a
template never blocks a payment email.

Which emails

eLinx notification emails

Each key has four parts: elinx.<event>.<product case>.<role>.

PartValues
eventconfirmation, first_notification, cancellation, expired, decline, reminder, funds_deposit, scheduled_failure, payment_failed, upcoming_payment
product caseone_time_collect, one_time_pay, recurring_collect, recurring_pay, beneficiary, or any
rolereceiver, sender, or any

Example: elinx.confirmation.one_time_collect.receiver is the confirmation email a receiver gets for
a one-time collection. elinx.decline.any.any is every decline email.

When an email is sent, we look for your template in this order and use the first one that exists:

  1. elinx.<event>.<product case>.<role> (exactly this email)
  2. elinx.<event>.any.<role> (this event and role, any product case)
  3. elinx.<event>.<product case>.any (this event and product case, either role)
  4. elinx.<event>.any.any (this event, everything)
  5. elinx.body (every eLinx email)

So you can supply one elinx.body template for everything and add more specific ones only where you
want different wording. The event is available inside the template ({!$Message.Event}), so a single
template can also use {!if} to vary its wording.

Transaction approval email

transaction_approval.single is the email sent to approvers when a transaction needs approval.

Template language

Templates use tags delimited by {! and }, so ordinary braces in CSS ({ color: red; }) need no
escaping. Write {!ldelim} / {!rdelim} for a literal {! or }.

{!$Message.Summary}                          print a value
{!$Message.GreetingName|default:'there'}     print a value with a fallback
{!if $Message.CtaUrl}...{!elseif $x}...{!else}...{!/if}
{!foreach $Message.FieldList as $Row}...{!/foreach}
{!* this is a comment *}

Allowed

  • Printing a variable, with dotted paths ($Message.Fields.Amount) and the loop properties
    @first, @last, @index, @iteration, @total (for example $Row@first).
  • {!if}, {!elseif}, {!else}, {!/if} using variables, quoted text, numbers, true/false/null
    and the operators == != > < >= <= eq ne gt lt gte lte and or not !.
  • {!foreach $List as $Item} (or as $Key => $Item), {!foreachelse}, {!/foreach}.
  • Comments, {!ldelim}, {!rdelim}.
  • Modifiers: escape, default, date_format, number_format, upper, lower, truncate,
    nl2br, replace. Arguments are quoted text or numbers: |truncate:80, |replace:'a':'b',
    |date_format:'%B %e, %Y', |number_format:2.

Not allowed

Anything else is rejected when we load the file, including {!assign}, {!include}, function and
method calls, {!php}, $smarty, backticks and backslashes inside a tag, and PHP tags. A PHP tag is
<?, ?>, <%, %> or <script language="php"> anywhere in the file, so write a percentage in HTML as
width="100&#37;", never width=100%>.

Limits

  • File size 256 KB; at most 2000 tags; blocks nested at most 10 deep.
  • {!foreach} cannot be nested inside another {!foreach}, and $Blocks cannot be used inside one.
  • A list (such as $Message.ScheduleRows) is cut to its first 1000 items.
  • Numbers written in a tag have at most 6 digits; |number_format takes 0 to 10 decimals and |truncate
    a length of 0 to 10000.
  • A tag has at most 3 modifiers, and at most one |escape, whose type must be html, htmlall, url or
    quotes (plain |escape means html).
  • The text written inside one {!foreach} is at most 16 KB, and each $Blocks.<Name> can be used at most
    twice in a template.
  • Modifiers work on single values only. A list or object ($Message, $Message.FieldList,
    $Message.Fields, a {!foreach} row such as $r) can be printed bare but cannot take a modifier;
    modify one field instead, for example {!$r.Amount|upper}.
  • A loop variable ($r in {!foreach $Message.ScheduleRows as $r}, and the key in $k => $v) only exists
    between its {!foreach} and {!/foreach}; using it after the loop is rejected.
  • Loop variable names must be unique in the template: each {!foreach} needs its own names, a name cannot
    be reused by a later loop, cannot be read anywhere outside its loop (before or after), and cannot be the
    name of a template variable (Message, Blocks, PartnerName, recipient_name, ...).
  • Nothing between {!foreachelse} and {!/foreach} may use the loop's variables ($r, $k); the loop
    has no rows there. Print other variables, such as $Message.Summary, instead.
  • Only plain {!$variable.path} references are accepted: no $variable::... and no $variable->....
  • A comment cannot contain {!.
  • Quoted text inside a tag: at most 1024 characters; the two texts of |replace at most 64
    characters each, and |replace at most once per tag. Double-quoted text cannot contain $, { or
    }; use single quotes.
  • Rendered output is capped at 2 MB. Before sending, we work out the most a template could produce from
    the data of that email (loops multiply their body by the number of rows, modifiers can grow a value).
    A template over the cap is not used and the standard email is sent instead. We check this when we load
    the file with sample data (an error) and with the longest possible lists (a warning: "may fall back to
    the default email for very long schedules").

Escaping: the one rule to remember

Values are prepared for you before your template runs:

  • Text values (names, amounts, labels) and URLs are already HTML-escaped. Print them as
    they are. Do not add |escape: it would show &amp;amp;. (We warn you when you do.)
  • HTML values are our own markup and are printed as-is (for example $Message.Summary, which
    contains bold amounts, and $Message.ExpiryLine).
  • $Blocks.* are ready-made pieces of our standard email, already rendered to HTML. Each is an
    empty string when it does not apply to the email being sent, so you can always print it.
  • A URL is only passed through when it starts with http:// or https://; otherwise it is empty.

Optional values may be empty: wrap them in {!if}. Only the variables listed below are available.

Variables

Every template can use these branding values.

VariableKindMeaning
$PrimaryColortextBrand colour for buttons, e.g. #FFD147
$ButtonTextColortextText colour on that button
$PartnerNametextBrand name
$WhitelabellingEnabledyes/noWhether the email is shown under your brand

eLinx emails (all elinx.* keys)

VariableKindMeaning
$Message.EventtextThe event, e.g. confirmation
$Message.SubjecttextOur standard subject
$Message.GreetingNametextName to greet
$Message.SummaryhtmlThe main sentence
$Message.FieldListlistDetail rows; each has Label and Value (text)
$Message.Fieldsmap of textThe same details by name, e.g. $Message.Fields.Amount, $Message.Fields.DueDate
$Message.ScheduleRowslistPayment schedule; each has Number, PaymentDate, Amount (text)
$Message.CtaLabeltextButton label (empty when there is no button)
$Message.CtaUrlurlButton link
$Message.DocumentUrlurlLink to a document
$Message.ExpiryLinehtml"This request expires on ..." line
$Message.SignOfftextSign-off name
$Blocks.DetailsCardhtmlOur details card
$Blocks.ScheduleTablehtmlOur payment schedule table
$Blocks.CtaButtonhtmlOur branded button
$Blocks.DocumentLinkhtmlOur document link

Subject tokens: {ReceiverName}, {SenderName}, {Amount}, {Frequency}, {FirstPaymentDate},
{ConnectionDate}, {DueDate}, {ExpiryDate}, {ScheduledDate}. A token with no value for a given
email becomes empty, so use the ones that make sense for the event. Example:
{SenderName} has requested {Amount}.

Transaction approval (transaction_approval.single)

VariableKindMeaning
$transaction_labeltextLabel for the ID row, e.g. "Transaction ID"
$transaction_idtextTransaction ID
$transaction_typetextType, e.g. "Payment"
$payment_railtextPayment method
$recipient_nametextWho is being paid
$currencytextCurrency code
$amountnumberAmount (use `number_format:2`)
$schedule_typetextSchedule, empty for a one-off
$date_submittedtextSubmission date and time
$has_invoiceyes/noWhether an invoice is attached
$invoice_numbertextInvoice number
$funding_introtextFunding explanation, may be empty
$funding_row_labeltextLabel of the funding row, may be empty
$funding_row_valuetextValue of the funding row
$funds_paymenttextFunding payment detail, may be empty
$consequencetextWhat happens on approval, may be empty
$is_funding_roleyes/noWhether the approver is the funding party
$urlurlThe approval link; every approval email should show it

Subject tokens: {TransactionID}, {Amount}, {Currency}, {RecipientName}, {PaymentRail}.

Subjects are limited to 255 characters and line breaks are removed.

Sample templates

All samples pass our checks as written; copy and adapt them.

eLinx (use as elinx.body, or for any specific elinx.* key)

{!* Example body for the eLinx key family. Replace the wording and styling freely. *}
<div style="font-family: Arial, sans-serif; color: #222222; font-size: 15px; line-height: 1.5;">
  <p>Hello {!$Message.GreetingName|default:'there'},</p>
  <p>{!$Message.Summary}</p>

  {!if $Message.FieldList}
  <table style="border-collapse: collapse; width: 100%; margin: 16px 0;">
    {!foreach $Message.FieldList as $Row}
    <tr>
      <td style="padding: 6px 8px; color: #666666;">{!$Row.Label}</td>
      <td style="padding: 6px 8px; font-weight: bold;">{!$Row.Value}</td>
    </tr>
    {!/foreach}
  </table>
  {!/if}

  {!if $Message.ScheduleRows}
  <table style="border-collapse: collapse; width: 100%; margin: 16px 0;">
    <tr><th align="left">#</th><th align="left">Payment date</th><th align="left">Amount</th></tr>
    {!foreach $Message.ScheduleRows as $Payment}
    <tr><td>{!$Payment.Number}</td><td>{!$Payment.PaymentDate}</td><td>{!$Payment.Amount}</td></tr>
    {!/foreach}
  </table>
  {!/if}

  {!if $Message.CtaUrl and $Message.CtaLabel}
  <p>
    <a href="{!$Message.CtaUrl}"
       style="display: inline-block; padding: 12px 24px; border-radius: 4px; text-decoration: none; background: {!$PrimaryColor}; color: {!$ButtonTextColor};">{!$Message.CtaLabel}</a>
  </p>
  {!/if}

  {!if $Message.DocumentUrl}
  <p><a href="{!$Message.DocumentUrl}">View the attached document</a></p>
  {!/if}

  {!if $Message.ExpiryLine}<p style="color: #666666;">{!$Message.ExpiryLine}</p>{!/if}

  {!* Our ready-made pieces are also available as the Blocks variables, e.g. DetailsCard or CtaButton *}
  <p>{!$Message.SignOff}</p>
</div>

eLinx, one specific email (elinx.confirmation.one_time_collect.receiver)

Used only for the confirmation sent to the person paying a one-time request. Every other eLinx email
keeps falling back to a broader key (or to our default). It reads single values by name from
$Message.Fields and drops in our ready-made $Blocks pieces.

{!* Example for one specific eLinx email: the confirmation sent to the person paying a one-time request.
   It reads single fields by name from $Message.Fields and reuses our ready-made Blocks. *}
<div style="font-family: Arial, sans-serif; color: #222222; font-size: 15px; line-height: 1.5;">
  <p>Hi {!$Message.GreetingName|default:'there'},</p>
  <p>Thanks, your payment is confirmed.</p>

  {!if $Message.Fields.Amount}
  <p style="font-size: 22px; font-weight: bold; margin: 16px 0;">{!$Message.Fields.Amount}</p>
  {!/if}
  {!if $Message.Fields.DueDate}
  <p style="color: #666666;">Due {!$Message.Fields.DueDate}</p>
  {!/if}

  {!* Our standard details card and button, already built with your branding colours *}
  {!$Blocks.DetailsCard}
  {!$Blocks.CtaButton}

  <p>{!$Message.SignOff}</p>
</div>

Transaction approval (transaction_approval.single)

{!* Example body for transaction_approval.single. *}
<div style="font-family: Arial, sans-serif; color: #222222; font-size: 15px; line-height: 1.5;">
  <p>A {!$transaction_type|lower} of <b>{!$currency} {!$amount|number_format:2}</b> to {!$recipient_name} is waiting for your approval.</p>

  <table style="border-collapse: collapse; margin: 16px 0;">
    <tr><td style="padding: 4px 12px 4px 0; color: #666666;">{!$transaction_label}</td><td>{!$transaction_id}</td></tr>
    <tr><td style="padding: 4px 12px 4px 0; color: #666666;">Payment method</td><td>{!$payment_rail}</td></tr>
    <tr><td style="padding: 4px 12px 4px 0; color: #666666;">Submitted</td><td>{!$date_submitted|date_format:'%B %e, %Y'}</td></tr>
    {!if $schedule_type}
    <tr><td style="padding: 4px 12px 4px 0; color: #666666;">Schedule</td><td>{!$schedule_type|upper}</td></tr>
    {!/if}
    {!if $has_invoice}
    <tr><td style="padding: 4px 12px 4px 0; color: #666666;">Invoice</td><td>{!$invoice_number|default:'-'}</td></tr>
    {!/if}
    {!if $is_funding_role and $funding_row_label}
    <tr><td style="padding: 4px 12px 4px 0; color: #666666;">{!$funding_row_label}</td><td>{!$funding_row_value}</td></tr>
    {!/if}
  </table>

  {!if $funding_intro}<p>{!$funding_intro}</p>{!/if}
  {!if $consequence}<p style="color: #666666;">{!$consequence}</p>{!/if}

  <p>
    <a href="{!$url}"
       style="display: inline-block; padding: 12px 24px; border-radius: 4px; text-decoration: none; background: {!$PrimaryColor}; color: {!$ButtonTextColor};">Review and approve</a>
  </p>
</div>

Did this page help you?