NOTICE: All information contained herein is, and remains
the property of TechnoCore Automate.
Updated : 2026-03-17
ObjTemplate manages templates stored in the database.
It supports two template stores:
$placeholder$ resolution| Column | Type | Description |
|---|---|---|
| TemplateCode | VARCHAR(64) | Primary key |
| Package | VARCHAR(255) | Package scope |
| Channel | VARCHAR(16) | Email / SMS / WhatsApp |
| Subject | VARCHAR(500) | Subject with |
| Body | LONGTEXT | HTML body with |
| Layout | VARCHAR(64) | Optional wrapper template code |
| Description | VARCHAR(500) | Human-readable description |
| Active | CHAR(1) | Y or N |
| Module | VARCHAR(255) | Module identifier |
| UpdateDate | DATETIME | Auto-updated timestamp |
Primary key: (TemplateCode, Package)
Templates use $placeholder$ tokens that are replaced
from a context dictionary at render time. Lookup is
case-insensitive.
<p>Dear $first_name$,</p>
<p>Your balance is R$balance$.</p>
If a template has a Layout value, that layout template
is loaded and the rendered body is inserted at the
$content$ marker:
<!-- Layout template: EMAIL_CHROME -->
<html>
<body style="font-family: Arial;">
<div style="max-width: 600px; margin: 0 auto;">
<img src="$logo_url$" />
$content$
<p style="font-size: 11px; color: #999;">
$company_name$ | $company_address$
</p>
</div>
</body>
</html>
Load and render an email template. Returns dict with
template_code, channel, subject, body.
from ObjTemplate import ObjTemplate
tpl = ObjTemplate()
result = tpl.render_email(
"WELCOME_EMAIL",
context={
"first_name": "Sipho",
"balance": "2981.72",
},
)
# result["subject"] = "Welcome, Sipho!"
# result["body"] = "<html>..."
Render and send in one call:
tpl.send_email(
"WELCOME_EMAIL",
"sipho@example.com",
context={"first_name": "Sipho"},
)
Insert or update a template:
tpl.save_email_template(
template_code="WELCOME_EMAIL",
subject="Welcome, $first_name$!",
body="<html>...$first_name$...</html>",
channel="Email",
layout="EMAIL_CHROME",
description="Welcome email for new customers",
)
List all templates for a package.
factory.core/extend.edit/ObjMailEdit.py is a mixin
(ObjEditBase, ObjTemplate) that exports / imports
single template rows between def_email_template and
YAML files under local.documents/email_templates/,
with a typer CLI (save, load, list). See
extend.edit/ObjMailEdit.md for full usage.
| TemplateCode | Engine | Used by |
|---|---|---|
JINJA2_TEST |
jinja2 | Integration test |
SIMULATION_OVERVIEW |
jinja2 | ObjReportDecisionSwitchSim — sim email body assembled from pre-rendered section variables (kpi_html, config_section, anomalies, distribution_section, outcomes, rules_section, summary_block, reconcile_block, raci_section). Subject: Decision Tree Sim: {{ decision_name }} v{{ version }} ({{ three_words }}). |
build_email_html() generates complete, branded HTML
emails using the package palette, logo, and signature.
All styles are inline (email clients strip <style>
blocks). Uses the same design language as
ObjWorkflowSimul simulation reports.
tpl = ObjTemplate()
body = ""
body += tpl.summary_box(
"Pipeline completed <strong>50</strong> rows."
)
body += tpl.section(
"Results",
["Metric", "Value"],
tpl.kv_row("Rows", "50")
+ tpl.kv_row("Status", "OK"),
)
html = tpl.build_email_html(
title="Pipeline Report",
body_html=body,
subtitle="creditscore_test | homechoice",
)
The email builder applies these inline styles using
the package palette colours:
| Element | Style |
|---|---|
<h2> |
Accent colour, 20px, bottom border |
<h3> |
Secondary colour, 16px |
<th> |
Accent background, white text, 14px |
<td> |
14px, bottom border |
<table> |
Collapsed borders, 100% width |
<p> |
Text colour, 14px, 1.6 line height |
| Method | Purpose |
|---|---|
section(title, headers, rows) |
Heading + table with bare tags |
kv_row(label, value) |
Two-column <tr> row |
summary_box(content) |
Blue-bordered highlight box |
build_email_html(title, body, subtitle) |
Full branded wrapper |
def_package)def_palette)def_package)send_email() reads SMTP credentials from config.yaml:
smtp:
server: smtp-relay.brevo.com
port: 587
username: xxx@smtp-brevo.com
password: secret
sender: noreply@example.com
Or pass remote_connection="WEBMASTER" to use
def_remoteconnections / config.yaml email.WEBMASTER.
Use with the SENDMAIL workflow node via template_code
in node_data:
{
"mode": "SINGLE",
"to": "team@example.com",
"template_code": "WF_RUN_COMPLETE",
"remote_connection": "smtp"
}
The SENDMAIL node enriches the context automatically:
ai.summary orai.default model from config.yaml$sections_html$ with all detailA generic workflow completion template (package-independent)
is provided. It uses $sections_html$ and $ai_summary$
to adapt to any workflow type automatically.
Templates can reference any workflow result key:
| Placeholder | Example Value |
|---|---|
$workflow$ |
CREDITSCORE_BATCH_RENDER |
$timestamp$ |
2026-03-17 15:50:36 |
$host$ |
Hyperion |
$total_elapsed_s$ |
0.59 |
$ai_summary$ |
AI-generated bullet points |
$sections_html$ |
Auto-built detail sections |
Any _key from run_context["result"] is available
as $key$ (with leading underscore stripped).
# Render an email template
python ObjTemplate.py render WF_BATCH_COMPLETE --template-type email
# List email templates
python ObjTemplate.py list-templates
# Send an email template
python ObjTemplate.py send WF_BATCH_COMPLETE --to user@example.com
# Save a template from an HTML file
python ObjTemplate.py save NEW_TEMPLATE \
--subject "Hello \$name\$" \
--body-file template.html \
--channel Email
read_page_template(template_name) reads from
def_template and resolves $placeholder$ tokens via
process_text(). Used for web page layouts.
ObjWebMail.py — SMTP email deliveryObjWorkflowSendMail.py — SENDMAIL workflow nodeObjFeatureRender.py — feature-driven template renderingUpdated : 2026-03-17