Template
Core library Template — HTML templates for messages (init, add, retrieve, update).
- SSJS
Template- SOAP
Template- mcdev
- not supported
- GUI
- Template
Deprecated. Template is a legacy Classic Content / Classic Email Studio feature. Salesforce retired classic content creation and editing (Classic Content reached end of life on 24 Apr 2023), and Content Builder is now the single cross-channel content repository. SOAP-era Template integrations only operate on the old Classic tools — prefer Content Builder assets (Asset REST endpoints) for new development.
Template manages template definitions (TemplateName, LayoutHTML, customer key, etc.). Use Retrieve with optional QueryAllAccounts: true to search across accessible accounts.
Requires Platform.Load("core", "1.1.5") before use.
Methods
| Method | Returns | Description |
|---|---|---|
Template.Init(key) |
TemplateInstance | Bind by external key |
Template.Add(properties) |
string | Create a template |
Template.Retrieve(filter) |
object[] | Query templates |
<TemplateInstance>.Update(properties) |
string | Update the initialized template |
Template.Init
Initializes a Template instance for the given external key.
Syntax
Template.Init(key)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
key |
string | Yes | External key |
Return value
TemplateInstance
Examples
Platform.Load("core", "1");
var t = Template.Init("myTemplate");
Show test script
<script runat="server">
Platform.Load("core", "1.1.5");
/*
* Chapter: Template.Init(key)
*
* CloudPage GET context. Proves:
* 1. Template requires the Core load and is then an object exposing the
* documented statics Init, Add and Retrieve.
* 2. There is no static Update / Remove — those are instance methods only.
* 3. Init(key) returns a TemplateInstance whose members are Update and
* Remove (each typeof "function"). Remove is present on the stub but
* is a no-op at runtime (cleanup uses WSProxy — see add/retrieve/
* instance-update scripts); this chapter only asserts the shape.
* 4. The instance carries NO readable template fields (CustomerKey,
* TemplateName, LayoutHTML, ID read back undefined) — Init binds a
* key, it does not fetch. Read fields via Template.Retrieve.
* 5. A nonsense key yields an indistinguishable stub.
* 6. The exact example shape on the page (Init("myTemplate")) runs.
*
* EXPECTED OUTPUT: every line starts with PASS.
*/
function assert(id, actual, expected) {
Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
function typeOf(fn) {
try { return "" + fn(); } catch (ex) { return "THREW"; }
}
function invocationResult(fn) {
try { fn(); return "returned"; } catch (ex) { return "threw"; }
}
assert("typeof Template is object", typeOf(function () { return typeof Template; }), "object");
assert("typeof Template.Init is function", typeOf(function () { return typeof Template.Init; }), "function");
assert("typeof Template.Add is function", typeOf(function () { return typeof Template.Add; }), "function");
assert("typeof Template.Retrieve is function", typeOf(function () { return typeof Template.Retrieve; }), "function");
assert("Template.Update is not a static", typeOf(function () { return typeof Template.Update; }), "undefined");
assert("Template.Remove is not a static", typeOf(function () { return typeof Template.Remove; }), "undefined");
var myTpl = Template.Init("ssjs-guide-ts-tpl-init");
assert("typeof Template.Init(key) is object", typeof myTpl, "object");
assert("typeof instance.Update is function", typeof myTpl.Update, "function");
assert("typeof instance.Remove is function", typeof myTpl.Remove, "function");
assert("instance has no Add", typeof myTpl.Add, "undefined");
assert("instance has no Retrieve", typeof myTpl.Retrieve, "undefined");
assert("instance exposes exactly Remove+Update", "" + Stringify(myTpl), '{"Remove":"function","Update":"function"}');
assert("instance.CustomerKey is undefined (Init does not fetch)", typeof myTpl.CustomerKey, "undefined");
assert("instance.TemplateName is undefined (Init does not fetch)", typeof myTpl.TemplateName, "undefined");
assert("instance.LayoutHTML is undefined (Init does not fetch)", typeof myTpl.LayoutHTML, "undefined");
assert("instance.ID is undefined (Init does not fetch)", typeof myTpl.ID, "undefined");
var bogus = Template.Init("ssjs-guide-no-such-tpl-zzz");
assert("Init(nonsense key) still returns an object", typeof bogus, "object");
assert("Init(nonsense key) exposes Update", typeof bogus.Update, "function");
assert("Init(nonsense key) stub is indistinguishable", ("" + Stringify(bogus)) === ("" + Stringify(myTpl)) ? "true" : "false", "true");
assert("page example: Init('myTemplate') returns", invocationResult(function () { return Template.Init("myTemplate"); }), "returned");
</script>
Template.Add
Creates a new template with the specified properties.
Syntax
Template.Add(properties)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
properties |
object | Yes | CustomerKey, TemplateName, LayoutHTML, … |
Return value
"OK" on success; "Error" on failure (does not throw).
Examples
Platform.Load("core", "1");
var myTemp = {
CustomerKey: "test_template",
TemplateName: "SSJS Test Template",
LayoutHTML: "this is some HTML"
};
var status = Template.Add(myTemp);
Show test script
<script runat="server">
Platform.Load("core", "1.1.5");
/*
* Chapter: Template.Add(properties)
*
* CloudPage GET context. Proves:
* 1. Template.Add is a function taking one properties object.
* 2. Add(properties) with the page example fields (CustomerKey,
* TemplateName, LayoutHTML) returns the string "OK" and creates a
* retrievable template.
* 3. Failures return the string "Error" and do NOT throw (Add() /
* Add({})) — callers must test the return value (DEV vs older catalog
* prose that claimed a throw).
* 4. Init instance has no Add (Add is static).
* 5. Instance.Remove is a no-op: after Remove the row still exists;
* cleanup uses WSProxy deleteItem and re-counts to 0.
*
* FIXTURE: ssjs-guide-ts-tpl-add — created and removed; orphan re-count 0.
*
* EXPECTED OUTPUT: every line starts with PASS.
*/
function assert(id, actual, expected) {
Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
function invocationResult(fn) {
try { fn(); return "returned"; } catch (ex) { return "threw"; }
}
function countByKey(key) {
var rows = Template.Retrieve({ Property: "CustomerKey", SimpleOperator: "equals", Value: key });
return rows && rows.length ? rows.length : 0;
}
function cleanupByKey(key) {
var api = new Script.Util.WSProxy();
var rows = Template.Retrieve({ Property: "CustomerKey", SimpleOperator: "equals", Value: key });
var i;
for (i = 0; i < (rows && rows.length ? rows.length : 0); i++) {
api.deleteItem("Template", { CustomerKey: "" + rows[i].CustomerKey, ID: rows[i].ID });
}
return countByKey(key);
}
var KEY = "ssjs-guide-ts-tpl-add";
assert("orphan cleanup pre-count is 0", "" + cleanupByKey(KEY), "0");
assert("typeof Template.Add is function", typeof Template.Add, "function");
assert("Init instance has no Add (Add is static)", typeof Template.Init(KEY).Add, "undefined");
var status = null;
assert("Add(properties) does not throw", invocationResult(function () {
status = Template.Add({
CustomerKey: KEY,
TemplateName: "SSJS Test Template",
LayoutHTML: "this is some HTML"
});
}), "returned");
assert("Add returns the string \"OK\"", "" + status, "OK");
assert("Add result typeof is string", typeof status, "string");
assert("the template exists after Add", "" + countByKey(KEY), "1");
assert("DEV Add() with no argument returns \"Error\" (does not throw; older catalog: throws)", "" + Template.Add(), "Error");
assert("Add() with no argument does NOT throw", invocationResult(function () { return Template.Add(); }), "returned");
assert("DEV Add({}) returns \"Error\" (does not throw; older catalog: throws)", "" + Template.Add({}), "Error");
/* Prove instance.Remove is a no-op so cleanup cannot rely on it. */
var removeRet = Template.Init(KEY).Remove();
assert("DEV instance.Remove returns undefined (does not delete)", typeof removeRet, "undefined");
assert("DEV instance.Remove left the row in place", "" + countByKey(KEY), "1");
assert("fixture cleanup via WSProxy re-count is 0", "" + cleanupByKey(KEY), "0");
</script>
Template.Retrieve
Queries templates matching the given filter. Pass { Filter: { Property, SimpleOperator, Value }, QueryAllAccounts: true } to search all accessible accounts.
Syntax
Template.Retrieve(filter)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
filter |
object | Yes | WSProxy-style filter (optionally with QueryAllAccounts) |
Return value
object[]
Examples
Platform.Load("core", "1.1.5");
var getTemplate = Template.Retrieve({
Property: "CustomerKey",
SimpleOperator: "equals",
Value: "MyTemplate"
});
Show test script
<script runat="server">
Platform.Load("core", "1.1.5");
/*
* Chapter: Template.Retrieve(filter)
*
* CloudPage GET context. Proves:
* 1. Retrieve is a function taking one PascalCase WSProxy-style filter.
* 2. On a match the result reports as [object Array], exposes .length,
* and is not a JS Array (instanceof Array is false).
* 3. A matched row exposes readable CustomerKey, TemplateName,
* LayoutHTML and numeric ID.
* 4. On no match the same array-like shape is returned with length 0
* and Stringify "[]".
* 5. The documented CustomerKey filter resolves the owned fixture.
* 6. The page's QueryAllAccounts wrapper shape
* { Filter, QueryAllAccounts: true } is accepted and returns the
* same array-like collection.
*
* FIXTURE: creates ssjs-guide-ts-tpl-retrieve and removes it at the end.
*
* EXPECTED OUTPUT: every line starts with PASS.
*/
function assert(id, actual, expected) {
Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
function countByKey(key) {
var rows = Template.Retrieve({ Property: "CustomerKey", SimpleOperator: "equals", Value: key });
return rows && rows.length ? rows.length : 0;
}
function cleanupByKey(key) {
var api = new Script.Util.WSProxy();
var rows = Template.Retrieve({ Property: "CustomerKey", SimpleOperator: "equals", Value: key });
var i;
for (i = 0; i < (rows && rows.length ? rows.length : 0); i++) {
api.deleteItem("Template", { CustomerKey: "" + rows[i].CustomerKey, ID: rows[i].ID });
}
return countByKey(key);
}
var KEY = "ssjs-guide-ts-tpl-retrieve";
cleanupByKey(KEY);
Template.Add({
CustomerKey: KEY,
TemplateName: "SSJS Guide TS Template Retrieve",
LayoutHTML: "retrieve probe HTML"
});
assert("typeof Template.Retrieve is function", typeof Template.Retrieve, "function");
var rows = Template.Retrieve({ Property: "CustomerKey", SimpleOperator: "equals", Value: KEY });
assert("typeof the matched result is object", typeof rows, "object");
assert("the matched result reports as [object Array]", Object.prototype.toString.call(rows), "[object Array]");
assert("the matched result exposes a numeric .length", typeof rows.length, "number");
assert("the matched result has exactly one row", "" + rows.length, "1");
assert("instanceof Array is false (engine-wide host-array quirk)", rows instanceof Array ? "true" : "false", "false");
assert("matched row CustomerKey equals the filter value", "" + rows[0].CustomerKey, KEY);
assert("matched row TemplateName is a string", typeof rows[0].TemplateName, "string");
assert("matched row LayoutHTML is a string", typeof rows[0].LayoutHTML, "string");
assert("matched row ID is a number", typeof rows[0].ID, "number");
assert("matched LayoutHTML equals the Add payload", "" + rows[0].LayoutHTML, "retrieve probe HTML");
var empty = Template.Retrieve({ Property: "CustomerKey", SimpleOperator: "equals", Value: "ssjs-guide-no-such-tpl-zzz" });
assert("empty result reports as [object Array]", Object.prototype.toString.call(empty), "[object Array]");
assert("empty result length is 0", "" + empty.length, "0");
assert("empty result Stringify is []", "" + Stringify(empty), "[]");
assert("workaround: guard with rows && rows.length before indexing", (rows && rows.length) ? "true" : "false", "true");
var qaa = Template.Retrieve({
Filter: { Property: "CustomerKey", SimpleOperator: "equals", Value: KEY },
QueryAllAccounts: true
});
assert("QueryAllAccounts wrapper reports as [object Array]", Object.prototype.toString.call(qaa), "[object Array]");
assert("QueryAllAccounts wrapper exposes numeric .length", typeof qaa.length, "number");
assert("QueryAllAccounts wrapper finds the fixture", qaa.length >= 1 ? "true" : "false", "true");
assert("fixture cleanup via WSProxy re-count is 0", "" + cleanupByKey(KEY), "0");
</script>
<TemplateInstance>.Update
Updates the initialized template with the given properties.
Syntax
<TemplateInstance>.Update(properties)
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
properties |
object | Yes | Attributes to change |
Return value
"OK" on success; "Error" on failure (does not throw).
Examples
Platform.Load("core", "1.1.5");
var myTemplate = Template.Init("myTemplateCK");
var status = myTemplate.Update({ TemplateName: "Edited Template" });
Show test script
<script runat="server">
Platform.Load("core", "1.1.5");
/*
* Chapter: <TemplateInstance>.Update(properties)
*
* CloudPage GET context. Proves:
* 1. Update is an instance method (typeof "function") on Template.Init.
* 2. Update(properties) returns the string "OK" on success.
* 3. The page example shape Update({ TemplateName }) succeeds and the
* new name is visible via Retrieve.
* 4. A repeated Update on the same key still returns "OK".
* 5. Negative case: Update on a nonexistent key returns "Error" (does
* not throw) — callers must test the return value (DEV vs older
* catalog prose that claimed a throw).
*
* FIXTURE: creates ssjs-guide-ts-tpl-update and removes it at the end.
*
* EXPECTED OUTPUT: every line starts with PASS.
*/
function assert(id, actual, expected) {
Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
function invocationResult(fn) {
try { fn(); return "returned"; } catch (ex) { return "threw"; }
}
function countByKey(key) {
var rows = Template.Retrieve({ Property: "CustomerKey", SimpleOperator: "equals", Value: key });
return rows && rows.length ? rows.length : 0;
}
function cleanupByKey(key) {
var api = new Script.Util.WSProxy();
var rows = Template.Retrieve({ Property: "CustomerKey", SimpleOperator: "equals", Value: key });
var i;
for (i = 0; i < (rows && rows.length ? rows.length : 0); i++) {
api.deleteItem("Template", { CustomerKey: "" + rows[i].CustomerKey, ID: rows[i].ID });
}
return countByKey(key);
}
var KEY = "ssjs-guide-ts-tpl-update";
cleanupByKey(KEY);
Template.Add({
CustomerKey: KEY,
TemplateName: "SSJS Guide TS Template Update",
LayoutHTML: "update probe HTML"
});
var myTemplate = Template.Init(KEY);
assert("typeof instance.Update is function", typeof myTemplate.Update, "function");
var status = myTemplate.Update({ TemplateName: "Edited Template" });
assert("page example: Update({TemplateName}) returns \"OK\"", "" + status, "OK");
assert("Update returns a string", typeof status, "string");
var after = Template.Retrieve({ Property: "CustomerKey", SimpleOperator: "equals", Value: KEY });
assert("Retrieve shows the updated TemplateName", "" + after[0].TemplateName, "Edited Template");
assert("a repeated Update on the same instance still returns \"OK\"", "" + myTemplate.Update({ LayoutHTML: "second update HTML" }), "OK");
assert("a freshly initialized instance for the same key also returns \"OK\"", "" + Template.Init(KEY).Update({ LayoutHTML: "third update HTML" }), "OK");
assert("DEV Update on a nonexistent key returns \"Error\" (does not throw; older catalog: throws)", "" + Template.Init("ssjs-guide-no-such-tpl-zzz").Update({ TemplateName: "x" }), "Error");
assert("Update on a nonexistent key does NOT throw", invocationResult(function () { return Template.Init("ssjs-guide-no-such-tpl-zzz").Update({ TemplateName: "x" }); }), "returned");
assert("fixture cleanup via WSProxy re-count is 0", "" + cleanupByKey(KEY), "0");
</script>