The TriggeredSend Core library object is the recommended way to send transactional emails from SSJS. It provides full lifecycle management of Triggered Send Definitions — create, retrieve, update, start, pause, publish, send, and track.

Methods

Method Returns Description
TriggeredSend.Init(key) TriggeredSendInstance Initialize a TriggeredSend object by external key
TriggeredSend.Add(properties) TriggeredSendInstance Create a new Triggered Send Definition
TriggeredSend.Retrieve(filter) object[] Retrieve Triggered Send Definitions matching a filter
<TriggeredSendInstance>.Update([properties]) string Update the initialized TSD (must not be Active)
<TriggeredSendInstance>.Start() string Start (reactivate) a paused TSD
<TriggeredSendInstance>.Pause() string Pause an active TSD
<TriggeredSendInstance>.Publish() string Publish a TSD to make it active
<TriggeredSendInstance>.Send(emailAddress, [sendTimeAttributes], [subscriberKey]) string Send an email using the TSD
<TriggeredSendInstance>.Tracking.Retrieve([filter]) object[] Retrieve tracking data for the TSD
<TriggeredSendInstance>.Tracking.Clicks.Retrieve(filter) object[] Retrieve click tracking data
<TriggeredSendInstance>.Tracking.TotalByInterval.Retrieve(type, startDate, endDate, groupBy) object[] Retrieve aggregated tracking data by interval

TriggeredSend.Init

Initializes a TriggeredSend instance bound to the specified external key. Required before invoking any instance method on the returned object.

Syntax

TriggeredSend.Init(key)

Parameters

Name Type Required Description
key string Yes External key of the Triggered Send Definition

Return value

TriggeredSendInstance

Examples

Platform.Load("core", "1");
var triggeredSend = TriggeredSend.Init("support");
Show test script
<script runat="server">
Platform.Load("core", "1.1.5");

/*
 * Chapter: TriggeredSend.Init(key)
 *
 * CloudPage GET context. Proves:
 *   1. TriggeredSend requires the Core load and exposes statics Init, Add,
 *      and Retrieve.
 *   2. Update / Start / Pause / Publish / Send / Tracking are instance-only
 *      (not statics on TriggeredSend).
 *   3. Init(key) returns a TriggeredSendInstance exposing Send, Start,
 *      Pause, Publish, Update, Tracking (Retrieve / Clicks.Retrieve /
 *      TotalByInterval.Retrieve), LastRequestID, and LastMessage.
 *   4. Init binds a key; it does not fetch readable fields (CustomerKey /
 *      Name / TriggeredSendStatus undefined on the stub).
 *   5. A nonsense key still returns an indistinguishable stub.
 *   6. The page example Init("support") returns without throwing.
 *
 * 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 TriggeredSend is object", typeOf(function () { return typeof TriggeredSend; }), "object");
assert("typeof TriggeredSend.Init is function", typeOf(function () { return typeof TriggeredSend.Init; }), "function");
assert("typeof TriggeredSend.Add is function", typeOf(function () { return typeof TriggeredSend.Add; }), "function");
assert("typeof TriggeredSend.Retrieve is function", typeOf(function () { return typeof TriggeredSend.Retrieve; }), "function");
assert("TriggeredSend.Update is not a static", typeOf(function () { return typeof TriggeredSend.Update; }), "undefined");
assert("TriggeredSend.Start is not a static", typeOf(function () { return typeof TriggeredSend.Start; }), "undefined");
assert("TriggeredSend.Pause is not a static", typeOf(function () { return typeof TriggeredSend.Pause; }), "undefined");
assert("TriggeredSend.Publish is not a static", typeOf(function () { return typeof TriggeredSend.Publish; }), "undefined");
assert("TriggeredSend.Send is not a static", typeOf(function () { return typeof TriggeredSend.Send; }), "undefined");

var ts = TriggeredSend.Init("ssjs-guide-ts-tsd-init");
assert("typeof TriggeredSend.Init(key) is object", typeof ts, "object");
assert("typeof instance.Update is function", typeof ts.Update, "function");
assert("typeof instance.Start is function", typeof ts.Start, "function");
assert("typeof instance.Pause is function", typeof ts.Pause, "function");
assert("typeof instance.Publish is function", typeof ts.Publish, "function");
assert("typeof instance.Send is function", typeof ts.Send, "function");
assert("typeof instance.Tracking is object", typeof ts.Tracking, "object");
assert("typeof Tracking.Retrieve is function", typeof ts.Tracking.Retrieve, "function");
assert("typeof Tracking.Clicks.Retrieve is function", typeof ts.Tracking.Clicks.Retrieve, "function");
assert("typeof Tracking.TotalByInterval.Retrieve is function", typeof ts.Tracking.TotalByInterval.Retrieve, "function");
assert("instance exposes documented members", "" + Stringify(ts), '{"Send":"function","Start":"function","Pause":"function","Publish":"function","Update":"function","Tracking":{"Retrieve":"function","Clicks":{"Retrieve":"function"},"TotalByInterval":{"Retrieve":"function"}},"LastRequestID":null,"LastMessage":null}');
assert("instance.CustomerKey is undefined (Init does not fetch)", typeof ts.CustomerKey, "undefined");
assert("instance.Name is undefined (Init does not fetch)", typeof ts.Name, "undefined");
assert("instance.TriggeredSendStatus is undefined (Init does not fetch)", typeof ts.TriggeredSendStatus, "undefined");

var bogus = TriggeredSend.Init("ssjs-guide-no-such-tsd-zzz");
assert("Init(nonsense key) still returns an object", typeof bogus, "object");
assert("Init(nonsense key) stub matches Init(fixture key)", ("" + Stringify(bogus)) === ("" + Stringify(ts)) ? "true" : "false", "true");
assert("page example: Init('support') returns", invocationResult(function () { return TriggeredSend.Init("support"); }), "returned");
</script>


TriggeredSend.Add

BlockedDiffers from docs

Does not work at runtime. Every invocation throws the string Error adding TSD. — verified against a fully valid, publishable definition. Use WSProxy createItem("TriggeredSendDefinition", ...) instead; with the identical payload it returns Status: "OK" and the resulting definition publishes, starts, sends, pauses and updates normally.

Creates a new triggered send definition from the supplied properties and returns an initialized TriggeredSend instance. Unlike most static Add methods, this returns a TriggeredSendInstance, not "OK".

Syntax

TriggeredSend.Add(properties)

Parameters

Name Type Required Description
properties object Yes Name, CustomerKey, FromName, FromAddress, EmailID, SendClassificationID, …

Return value

TriggeredSendInstance per the official documentation — never observed, see below.

Runtime behaviour

No working invocation exists. The method always throws the string Error adding TSD., and TriggeredSend.LastMessage is then one of:

Payload contains LastMessage LastErrorCode
Any nested object (Email, List, SendClassification) An error occurred when attempting to evaluate a SetObjectProperty function call. See inner exception for details. undefined / 2
Flat scalar properties only Error adding TSD. 17014 / 2
A string, or two arguments Error adding TSD.

Payload shapes swept, all failing: nested SOAP shape (Email: {ID}, List: {ID}, SendClassification: {CustomerKey} or {ObjectID}), the documented flat shape (EmailID, ListID, SendClassificationID), dotted keys ("Email.ID"), scalar-only payloads, typed Core Library objects (Email.Init(), List.Init(), SendClassification.Init()), and the CLR object returned by TriggeredSend.Retrieve with its CustomerKey mutated.

Working alternative

Platform.Load("core", "1.1.5");
var api = new Script.Util.WSProxy();

var result = api.createItem("TriggeredSendDefinition", {
    CustomerKey: "ssjs_tsd_key",
    Name: "Test TSD",
    Description: "created via WSProxy",
    Email: { ID: 769268 },
    List: { ID: 72164 },
    SendClassification: { CustomerKey: "Default Transactional" },
    TriggeredSendType: "Continuous",
    AutoAddSubscribers: true,
    AutoUpdateSubscribers: false,
    BatchInterval: 0,
    IsMultipart: false,
    IsWrapped: true,
    FromName: "Test From Name",
    FromAddress: "me@example.com",
    EmailSubject: "Test"
});
// result.Status === "OK", result.Results[0].StatusMessage === "TriggeredSendDefinition created"

var tsd = TriggeredSend.Init("ssjs_tsd_key");

Examples

Platform.Load("core", "1.1.5");
var newTSD = {
    Name: "Test TSD",
    CustomerKey: "ssjs_tsd_key",
    FromName: "Test From Name",
    FromAddress: "me@example.com",
    EmailID: 12345,
    SendClassificationID: 54321
};
var tsd = TriggeredSend.Add(newTSD); // throws "Error adding TSD."

See also Known Bugs and Differs from Official Docs.

Show test script
<script runat="server">
Platform.Load("core", "1.1.5");

/*
 * Chapter: TriggeredSend.Add(properties) — blocked / non-functional
 *
 * CloudPage GET context. Proves:
 *   1. Add is a static function.
 *   2. Flat scalar payload throws the string "Error adding TSD."
 *   3. After that throw, LastMessage is "Error adding TSD." and
 *      LastErrorCode is 2 (page table: 17014 / 2 for flat-only).
 *   4. Nested-object payload also throws "Error adding TSD."; LastMessage
 *      then mentions SetObjectProperty.
 *   5. DEV: string / two-argument forms also throw "Error adding TSD."
 *      (older note / Update("x") path: Invalid cast from 'Char' to 'Double').
 *   6. Workaround: WSProxy createItem("TriggeredSendDefinition", ...) with
 *      a valid payload returns Status "OK" / StatusMessage created; then
 *      TriggeredSend.Init(key) binds the new definition. (Publish/Start of
 *      that definition is NON-ASSERTABLE here — see bundle header.)
 *
 * EXPECTED OUTPUT: every line starts with PASS.
 */

function assert(id, actual, expected) {
    Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
function catchKind(fn) {
    try { fn(); return "did-not-throw"; }
    catch (ex) {
        var t = typeof ex;
        var s = (t === "string") ? ("" + ex) : ("" + (ex && ex.message));
        return t + "|" + s;
    }
}

var api = new Script.Util.WSProxy();
var EM = "ssjs-guide-ts-tsd-add-email";
var LI = "ssjs-guide-ts-tsd-add-list";
var TSD = "ssjs-guide-ts-tsd-add";
try { api.deleteItem("TriggeredSendDefinition", { CustomerKey: TSD }); } catch (e0) {}
try { Email.Init(EM).Remove(); } catch (e1) {}
try { List.Init(LI).Remove(); } catch (e2) {}

assert("typeof TriggeredSend.Add is function", typeof TriggeredSend.Add, "function");

assert("DEV flat Add throws string Error adding TSD. (docs: returns TriggeredSendInstance)", catchKind(function () {
    return TriggeredSend.Add({
        Name: "x", CustomerKey: TSD + "-flat", FromName: "n",
        FromAddress: "a@b.com", EmailID: 1, SendClassificationID: 1
    });
}), "string|Error adding TSD.");
assert("flat Add LastMessage is Error adding TSD.", (("" + TriggeredSend.LastMessage).indexOf("Error adding TSD.") >= 0) ? "matched" : ("" + TriggeredSend.LastMessage), "matched");
assert("flat Add LastErrorCode is 2", "" + TriggeredSend.LastErrorCode, "2");

assert("DEV nested Add throws string Error adding TSD. (docs: returns instance)", catchKind(function () {
    return TriggeredSend.Add({
        Name: "x", CustomerKey: TSD + "-nest",
        Email: { ID: 1 }, List: { ID: 1 },
        SendClassification: { CustomerKey: "Default Transactional" }
    });
}), "string|Error adding TSD.");
assert("nested Add LastMessage mentions SetObjectProperty", (("" + TriggeredSend.LastMessage).indexOf("SetObjectProperty") >= 0) ? "matched" : ("" + TriggeredSend.LastMessage), "matched");

assert("DEV Add('x') throws Error adding TSD. (older note: Invalid cast Char to Double)", catchKind(function () {
    return TriggeredSend.Add("x");
}), "string|Error adding TSD.");
assert("DEV Add(obj, 'x') throws Error adding TSD. (older note: Invalid cast Char to Double)", catchKind(function () {
    return TriggeredSend.Add({ Name: "x" }, "x");
}), "string|Error adding TSD.");

Email.Add({
    CustomerKey: EM, Name: "SSJS Guide TS TSD Add Email",
    HTMLBody: "<b>add</b>", TextBody: "add",
    Subject: "SSJS Guide TSD Add", EmailType: "HTML", CharacterSet: "US-ASCII"
});
List.Add({ CustomerKey: LI, Name: "SSJS Guide TS TSD Add List", Type: "Public" });
var emailId = Email.Retrieve({ Property: "CustomerKey", SimpleOperator: "equals", Value: EM })[0].ID;
var listId = List.Retrieve({ Property: "CustomerKey", SimpleOperator: "equals", Value: LI })[0].ID;

var createRes = api.createItem("TriggeredSendDefinition", {
    CustomerKey: TSD,
    Name: "SSJS Guide TS TSD Add",
    Description: "workaround fixture",
    Email: { ID: emailId },
    List: { ID: listId },
    SendClassification: { CustomerKey: "ssjs-sendclassification-transactiona" },
    TriggeredSendType: "Continuous",
    AutoAddSubscribers: true,
    AutoUpdateSubscribers: false,
    BatchInterval: 0,
    IsMultipart: false,
    IsWrapped: true,
    FromName: "SSJS Probe",
    FromAddress: "joern.berkefeld@accenture.com",
    EmailSubject: "SSJS Guide TSD Add"
});
assert("workaround WSProxy createItem Status is OK", "" + createRes.Status, "OK");
assert("workaround StatusMessage is TriggeredSendDefinition created", "" + createRes.Results[0].StatusMessage, "TriggeredSendDefinition created");
assert("workaround Init binds the new key", typeof TriggeredSend.Init(TSD).Send, "function");
assert("workaround Retrieve finds the new record", "" + TriggeredSend.Retrieve({ Property: "CustomerKey", SimpleOperator: "equals", Value: TSD }).length, "1");

api.deleteItem("TriggeredSendDefinition", { CustomerKey: TSD });
assert("TSD orphan count 0", "" + TriggeredSend.Retrieve({ Property: "CustomerKey", SimpleOperator: "equals", Value: TSD }).length, "0");
assert("fixture email removed", "" + Email.Init(EM).Remove(), "OK");
assert("fixture list removed", "" + List.Init(LI).Remove(), "OK");
assert("email orphan count 0", "" + Email.Retrieve({ Property: "CustomerKey", SimpleOperator: "equals", Value: EM }).length, "0");
assert("list orphan count 0", "" + List.Retrieve({ Property: "CustomerKey", SimpleOperator: "equals", Value: LI }).length, "0");
</script>


TriggeredSend.Retrieve

Returns an array of triggered send definitions matching the specified filter.

Syntax

TriggeredSend.Retrieve(filter)

Parameters

Name Type Required Description
filter object Yes PascalCase WSProxy-style filter object: {Property, SimpleOperator, Value}

Return value

object[]

Examples

Platform.Load("core", "1.1.5");
var results = TriggeredSend.Retrieve({ Property: "CustomerKey", SimpleOperator: "equals", Value: "ssjs_tsd_key" });
Show test script
<script runat="server">
Platform.Load("core", "1.1.5");

/*
 * Chapter: TriggeredSend.Retrieve(filter)
 *
 * CloudPage GET context. Proves:
 *   1. Retrieve is a function taking one PascalCase WSProxy-style filter.
 *   2. Matched / empty results report as [object Array] with .length;
 *      instanceof Array is false (engine-wide host-array quirk).
 *   3. A matched row exposes readable CustomerKey and TriggeredSendStatus.
 *
 * FIXTURE: WSProxy-created New TSD under ssjs-guide-ts-tsd-ret*.
 * EXPECTED OUTPUT: every line starts with PASS.
 */

function assert(id, actual, expected) {
    Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}

var api = new Script.Util.WSProxy();
var EM = "ssjs-guide-ts-tsd-ret-email";
var LI = "ssjs-guide-ts-tsd-ret-list";
var TSD = "ssjs-guide-ts-tsd-ret";
try { api.deleteItem("TriggeredSendDefinition", { CustomerKey: TSD }); } catch (e0) {}
try { Email.Init(EM).Remove(); } catch (e1) {}
try { List.Init(LI).Remove(); } catch (e2) {}

Email.Add({
    CustomerKey: EM, Name: "SSJS Guide TS TSD Ret Email",
    HTMLBody: "<b>ret</b>", TextBody: "ret",
    Subject: "SSJS Guide TSD Ret", EmailType: "HTML", CharacterSet: "US-ASCII"
});
List.Add({ CustomerKey: LI, Name: "SSJS Guide TS TSD Ret List", Type: "Public" });
var emailId = Email.Retrieve({ Property: "CustomerKey", SimpleOperator: "equals", Value: EM })[0].ID;
var listId = List.Retrieve({ Property: "CustomerKey", SimpleOperator: "equals", Value: LI })[0].ID;
api.createItem("TriggeredSendDefinition", {
    CustomerKey: TSD, Name: "SSJS Guide TS TSD Ret",
    Email: { ID: emailId }, List: { ID: listId },
    SendClassification: { CustomerKey: "ssjs-sendclassification-transactiona" },
    TriggeredSendType: "Continuous", AutoAddSubscribers: true, IsWrapped: true,
    FromName: "SSJS Probe", FromAddress: "joern.berkefeld@accenture.com",
    EmailSubject: "SSJS Guide TSD Ret"
});

assert("typeof TriggeredSend.Retrieve is function", typeof TriggeredSend.Retrieve, "function");
var rows = TriggeredSend.Retrieve({ Property: "CustomerKey", SimpleOperator: "equals", Value: TSD });
assert("matched Retrieve reports as [object Array]", Object.prototype.toString.call(rows), "[object Array]");
assert("matched Retrieve instanceof Array is false", rows instanceof Array ? "true" : "false", "false");
assert("matched Retrieve length is 1", "" + rows.length, "1");
assert("matched CustomerKey", "" + rows[0].CustomerKey, TSD);
assert("matched TriggeredSendStatus is New", "" + rows[0].TriggeredSendStatus, "New");

var empty = TriggeredSend.Retrieve({ Property: "CustomerKey", SimpleOperator: "equals", Value: "ssjs-guide-no-such-tsd-zzz" });
assert("empty Retrieve reports as [object Array]", Object.prototype.toString.call(empty), "[object Array]");
assert("empty Retrieve length is 0", "" + empty.length, "0");
assert("empty Retrieve Stringify is []", "" + Stringify(empty), "[]");

api.deleteItem("TriggeredSendDefinition", { CustomerKey: TSD });
assert("TSD orphan count 0", "" + TriggeredSend.Retrieve({ Property: "CustomerKey", SimpleOperator: "equals", Value: TSD }).length, "0");
Email.Init(EM).Remove();
List.Init(LI).Remove();
assert("email orphan count 0", "" + Email.Retrieve({ Property: "CustomerKey", SimpleOperator: "equals", Value: EM }).length, "0");
assert("list orphan count 0", "" + List.Retrieve({ Property: "CustomerKey", SimpleOperator: "equals", Value: LI }).length, "0");
</script>


<TriggeredSendInstance>.Update

Updates the previously initialized triggered send definition.

Syntax

<TriggeredSendInstance>.Update([properties])

Parameters

Name Type Required Description
properties object No Attributes to change on the triggered send definition. Officially required, but omitting it returns "OK" at runtime.

Return value

"OK" on success, "Error" when the definition is Active.

Runtime behaviour

Call Result
Update({ Description: "..." }) on an Inactive TSD "OK", LastMessage TriggeredSendDefinition updated — change persisted
Update({ ... }) on an Active TSD "Error", code 17003
Update() — no arguments "OK" (no change applied)
Update("x") — non-object throws Error Updating TSD., LastMessage Invalid cast from 'Char' to 'Double'.

Examples

Platform.Load("core", "1.1.5");
var tsd = TriggeredSend.Init("triggeredSend");

tsd.Pause();                                        // required — cannot update while Active
var status = tsd.Update({ Name: "Updated TSD Name" }); // "OK"
tsd.Start();                                        // reactivate
Show test script
<script runat="server">
Platform.Load("core", "1.1.5");

/*
 * Chapter: <TriggeredSendInstance>.Update([properties])
 *
 * CloudPage GET context. Proves:
 *   1. Update is an instance method.
 *   2. Update("x") throws string "Error Updating TSD." with LastMessage
 *      Invalid cast from 'Char' to 'Double'.
 *
 * NON-ASSERTABLE: Update({...}) / Update() returning "OK" on Inactive, and
 * Active → "Error" / LastErrorCode 17003 — need a publishable TSD (bundle
 * header). Differs callouts for optional properties + Active reject are
 * likewise blocked in this environment.
 *
 * EXPECTED OUTPUT: every line starts with PASS.
 */

function assert(id, actual, expected) {
    Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
function catchKind(fn) {
    try { fn(); return "did-not-throw"; }
    catch (ex) {
        var t = typeof ex;
        var s = (t === "string") ? ("" + ex) : ("" + (ex && ex.message));
        return t + "|" + s;
    }
}

var ts = TriggeredSend.Init("ssjs-guide-ts-tsd-update");
assert("typeof instance.Update is function", typeof ts.Update, "function");
assert("Update('x') throws Error Updating TSD.", catchKind(function () { return ts.Update("x"); }), "string|Error Updating TSD.");
assert("Update('x') LastMessage is Invalid cast from Char to Double", "" + ts.LastMessage, "Invalid cast from 'Char' to 'Double'.");
</script>


<TriggeredSendInstance>.Start

Starts (reactivates) a paused triggered send definition. This is the call that actually sets TriggeredSendStatus to Active — see Publish.

Syntax

<TriggeredSendInstance>.Start()

Return value

"OK" on success, with LastMessage TriggeredSendDefinition updated.

Runtime behaviour

Verified: the definition’s TriggeredSendStatus becomes Active immediately afterwards. Surplus arguments are ignored rather than rejected — Start("x") also returns "OK".

Examples

Platform.Load("core", "1.1.5");
var ts = TriggeredSend.Init("MY_TRIGGERED_SEND_KEY");
var result = ts.Start(); // "OK" -> status is now Active
Show test script
<script runat="server">
Platform.Load("core", "1.1.5");

/*
 * Chapter: <TriggeredSendInstance>.Start()
 *
 * CloudPage GET context. Proves:
 *   1. Start is an instance method.
 *
 * NON-ASSERTABLE: Start() / Start("x") returning "OK" and moving
 * TriggeredSendStatus to Active — needs a publishable TSD (bundle header).
 * Differs surplus-args callout blocked for the same reason.
 *
 * EXPECTED OUTPUT: every line starts with PASS.
 */

function assert(id, actual, expected) {
    Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}

var ts = TriggeredSend.Init("ssjs-guide-ts-tsd-start");
assert("typeof instance.Start is function", typeof ts.Start, "function");
</script>


<TriggeredSendInstance>.Pause

Pauses an active triggered send definition. Required before Update.

Syntax

<TriggeredSendInstance>.Pause()

Return value

"OK" on success, with LastMessage TriggeredSendDefinition updated.

Runtime behaviour

Verified: the definition’s TriggeredSendStatus becomes Inactive — note the resulting status is Inactive, not Paused. Surplus arguments are ignored rather than rejected — Pause("x") also returns "OK".

Examples

Platform.Load("core", "1.1.5");
var ts = TriggeredSend.Init("MY_TRIGGERED_SEND_KEY");
var status = ts.Pause(); // "OK" -> status is now Inactive
Show test script
<script runat="server">
Platform.Load("core", "1.1.5");

/*
 * Chapter: <TriggeredSendInstance>.Pause()
 *
 * CloudPage GET context. Proves:
 *   1. Pause is an instance method.
 *
 * NON-ASSERTABLE: Pause() / Pause("x") returning "OK" and read-back status
 * "Inactive" (not "Paused") — needs a publishable Active TSD (bundle header).
 *
 * EXPECTED OUTPUT: every line starts with PASS.
 */

function assert(id, actual, expected) {
    Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}

var ts = TriggeredSend.Init("ssjs-guide-ts-tsd-pause");
assert("typeof instance.Pause is function", typeof ts.Pause, "function");
</script>


<TriggeredSendInstance>.Publish

Publishes a triggered send definition. The official documentation describes this as making the definition active and ready to accept sends; at runtime the status change to Active comes from Start.

Syntax

<TriggeredSendInstance>.Publish()

Return value

"OK" on success, with LastMessage TriggeredSendDefinition updated.

Runtime behaviour

Verified on a New definition: Publish() returned "OK" but a follow-up retrieve still reported TriggeredSendStatus: "New"; the subsequent Start() moved it to Active. Surplus arguments are ignored rather than rejected — Publish("x") also returns "OK".

Examples

Platform.Load("core", "1.1.5");
var ts = TriggeredSend.Init("MY_TRIGGERED_SEND_KEY");
ts.Publish(); // "OK" - status still New
ts.Start();   // "OK" - status now Active
Show test script
<script runat="server">
Platform.Load("core", "1.1.5");

/*
 * Chapter: <TriggeredSendInstance>.Publish()
 *
 * CloudPage GET context. Proves:
 *   1. Publish is an instance method.
 *
 * NON-ASSERTABLE: Publish() / Publish("x") returning "OK" while status stays
 * "New" until Start() — needs a TSD whose email passes Triggered-Send
 * validation (bundle header).
 *
 * EXPECTED OUTPUT: every line starts with PASS.
 */

function assert(id, actual, expected) {
    Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}

var ts = TriggeredSend.Init("ssjs-guide-ts-tsd-publish");
assert("typeof instance.Publish is function", typeof ts.Publish, "function");
</script>


<TriggeredSendInstance>.Send

A third argument is accepted at runtime: Send(emailAddress, sendTimeAttributes, subscriberKey). The definition also does not have to be Active — a send against an Inactive definition still returned "OK".

Sends an email using the previously initialized triggered send definition. On failure, inspect <TriggeredSendInstance>.LastMessage for error details.

Syntax

<TriggeredSendInstance>.Send(emailAddress, [sendTimeAttributes], [subscriberKey])

Parameters

Name Type Required Description
emailAddress string Yes Email address to send to. SubscriberKey is not supported here — use the third argument.
sendTimeAttributes object No Dynamic attributes to include in the send
subscriberKey string No Undocumented third argument accepted at runtime — subscriber key to associate with the send
Show test script — invalid Send returns "Error"
<script runat="server">
Platform.Load("core", "1.1.5");

/*
 * Differs: invalid Send returns "Error" instead of throwing.
 * On a New TSD (publishable Active path NON-ASSERTABLE), Send(invalid)
 * still returns "Error" without throwing — that is the differs claim.
 * 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"; }
}

var api = new Script.Util.WSProxy();
var EM = "ssjs-guide-ts-tsd-senderr-email";
var LI = "ssjs-guide-ts-tsd-senderr-list";
var TSD = "ssjs-guide-ts-tsd-senderr";
try { api.deleteItem("TriggeredSendDefinition", { CustomerKey: TSD }); } catch (e0) {}
try { Email.Init(EM).Remove(); } catch (e1) {}
try { List.Init(LI).Remove(); } catch (e2) {}
Email.Add({
    CustomerKey: EM, Name: "SSJS Guide TS TSD SendErr Email",
    HTMLBody: "<b>e</b>", TextBody: "e", Subject: "e", EmailType: "HTML", CharacterSet: "US-ASCII"
});
List.Add({ CustomerKey: LI, Name: "SSJS Guide TS TSD SendErr List", Type: "Public" });
var emailId = Email.Retrieve({ Property: "CustomerKey", SimpleOperator: "equals", Value: EM })[0].ID;
var listId = List.Retrieve({ Property: "CustomerKey", SimpleOperator: "equals", Value: LI })[0].ID;
api.createItem("TriggeredSendDefinition", {
    CustomerKey: TSD, Name: "SSJS Guide TS TSD SendErr",
    Email: { ID: emailId }, List: { ID: listId },
    SendClassification: { CustomerKey: "ssjs-sendclassification-transactiona" },
    TriggeredSendType: "Continuous", AutoAddSubscribers: true, IsWrapped: true,
    FromName: "SSJS Probe", FromAddress: "joern.berkefeld@accenture.com",
    EmailSubject: "e"
});
var ts = TriggeredSend.Init(TSD);
var status = null;
assert("DEV invalid Send does NOT throw (docs: errors)", invocationResult(function () { status = ts.Send("not-an-address"); }), "returned");
assert("DEV invalid Send returns \"Error\" (docs: throw/error)", "" + status, "Error");
api.deleteItem("TriggeredSendDefinition", { CustomerKey: TSD });
Email.Init(EM).Remove();
List.Init(LI).Remove();
</script>

Return value

"OK" on success, with LastMessage Created TriggeredSend.

Runtime behaviour

Call Result
Send("valid@example.com") "OK", LastMessage Created TriggeredSend, mail delivered
Send(addr, attrs, "subKey") "OK" — third argument accepted; a fourth is ignored
Definition is Inactive still "OK" — active status is not enforced by this call
Send("not-an-address") returns "Error" (does not throw), LastMessage Unable to queue Triggered Send request. There are no valid subscribers.
Send() — no arguments throws Usage: Send(EmailAddress [, sendTimeAttributes])

LastRequestID was 0 after a successful send rather than a request GUID.

Examples

Simple Send

Platform.Load("core", "1.1.5");
var ts = TriggeredSend.Init("triggeredSend");
var status = ts.Send("aruiz@example.com", { FirstName: "Angel", CouponCode: "AA1AF" });
if (status != "OK") { var message = ts.LastMessage; }

Order Confirmation

Platform.Load("core", "1.1.5");

var rawBody = Platform.Request.GetPostData();
var order = Platform.Function.ParseJSON(rawBody + "");

var ts = TriggeredSend.Init("OrderConfirmation_TSD");
var status = ts.Send(order.email, {
    OrderNumber: order.orderNumber,
    Total: order.total,
    ShippingAddress: order.shippingAddress
});

Platform.Response.ContentType = "application/json";
Write(Stringify({ status: status, order: order.orderNumber }));
Show test script
<script runat="server">
Platform.Load("core", "1.1.5");

/*
 * Chapter: <TriggeredSendInstance>.Send(emailAddress, [attrs], [subscriberKey])
 *
 * CloudPage GET context. Proves:
 *   1. Send is an instance method.
 *   2. Send() with no arguments throws Usage: Send(EmailAddress [, sendTimeAttributes]).
 *   3. DEV vs Active-path docs: on a New (not publishable) definition,
 *      Send("not-an-address") returns the string "Error" and does NOT throw
 *      (differs: failures are status strings). LastMessage mentions new /
 *      not completely configured rather than the Active-path
 *      "no valid subscribers" text — that Active invalid-address message,
 *      plus Send OK / Inactive OK / third subscriberKey, are NON-ASSERTABLE
 *      without a publishable TSD (bundle header). No real inbox send is
 *      performed.
 *
 * FIXTURE: WSProxy New TSD ssjs-guide-ts-tsd-send*.
 * EXPECTED OUTPUT: every line starts with PASS.
 */

function assert(id, actual, expected) {
    Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}
function catchKind(fn) {
    try { fn(); return "did-not-throw"; }
    catch (ex) {
        var t = typeof ex;
        var s = (t === "string") ? ("" + ex) : ("" + (ex && ex.message));
        return t + "|" + s;
    }
}
function invocationResult(fn) {
    try { fn(); return "returned"; } catch (ex) { return "threw"; }
}

var api = new Script.Util.WSProxy();
var EM = "ssjs-guide-ts-tsd-send-email";
var LI = "ssjs-guide-ts-tsd-send-list";
var TSD = "ssjs-guide-ts-tsd-send";
try { api.deleteItem("TriggeredSendDefinition", { CustomerKey: TSD }); } catch (e0) {}
try { Email.Init(EM).Remove(); } catch (e1) {}
try { List.Init(LI).Remove(); } catch (e2) {}

Email.Add({
    CustomerKey: EM, Name: "SSJS Guide TS TSD Send Email",
    HTMLBody: "<b>send</b>", TextBody: "send",
    Subject: "SSJS Guide TSD Send", EmailType: "HTML", CharacterSet: "US-ASCII"
});
List.Add({ CustomerKey: LI, Name: "SSJS Guide TS TSD Send List", Type: "Public" });
var emailId = Email.Retrieve({ Property: "CustomerKey", SimpleOperator: "equals", Value: EM })[0].ID;
var listId = List.Retrieve({ Property: "CustomerKey", SimpleOperator: "equals", Value: LI })[0].ID;
api.createItem("TriggeredSendDefinition", {
    CustomerKey: TSD, Name: "SSJS Guide TS TSD Send",
    Email: { ID: emailId }, List: { ID: listId },
    SendClassification: { CustomerKey: "ssjs-sendclassification-transactiona" },
    TriggeredSendType: "Continuous", AutoAddSubscribers: true, IsWrapped: true,
    FromName: "SSJS Probe", FromAddress: "joern.berkefeld@accenture.com",
    EmailSubject: "SSJS Guide TSD Send"
});

var ts = TriggeredSend.Init(TSD);
assert("typeof instance.Send is function", typeof ts.Send, "function");
assert("Send() with no args throws usage string", catchKind(function () { return ts.Send(); }), "string|Usage: Send(EmailAddress [, sendTimeAttributes])");

var bad = null;
assert("DEV Send(invalid) on New returns without throwing (docs: error / Active path)", invocationResult(function () {
    bad = ts.Send("not-an-address");
}), "returned");
assert("DEV Send(invalid) on New returns string Error (docs: may throw)", "" + bad, "Error");
assert("DEV New-status LastMessage mentions not completely configured (Active path: no valid subscribers)", (("" + ts.LastMessage).indexOf("not completely configured") >= 0 || ("" + ts.LastMessage).indexOf("new status") >= 0) ? "matched" : ("" + ts.LastMessage), "matched");

api.deleteItem("TriggeredSendDefinition", { CustomerKey: TSD });
assert("TSD orphan count 0", "" + TriggeredSend.Retrieve({ Property: "CustomerKey", SimpleOperator: "equals", Value: TSD }).length, "0");
Email.Init(EM).Remove();
List.Init(LI).Remove();
assert("email orphan count 0", "" + Email.Retrieve({ Property: "CustomerKey", SimpleOperator: "equals", Value: EM }).length, "0");
assert("list orphan count 0", "" + List.Retrieve({ Property: "CustomerKey", SimpleOperator: "equals", Value: LI }).length, "0");
</script>

Notes

Triggered Send Definition status

The official guidance is that the Triggered Send Definition must be in Active status in Email Studio (Interactions → Triggered Emails). At runtime this was not enforced by Send — a send against an Inactive definition still returned "OK" with LastMessage Created TriggeredSend. Keep the definition Active anyway; do not rely on the unenforced behaviour.

Attributes are case-sensitive

The attribute keys in sendTimeAttributes must exactly match the AMPscript variable names used in the email template (without the @ prefix).


<TriggeredSendInstance>.Tracking.Retrieve

Returns tracking data for the previously initialized triggered send definition.

Syntax

<TriggeredSendInstance>.Tracking.Retrieve([filter])

Parameters

Name Type Required Description
filter object No Optional WSProxy-style filter object

Return value

object[]

Examples

Platform.Load("core", "1.1.5");
var tsd = TriggeredSend.Init("MyTSDKey");
var tsdTracking = tsd.Tracking.Retrieve();
Show test script
<script runat="server">
Platform.Load("core", "1.1.5");

/*
 * Chapter: <TriggeredSendInstance>.Tracking.Retrieve([filter])
 *
 * CloudPage GET context. Proves:
 *   1. Tracking.Retrieve is an instance function (optional filter).
 *   2. No-arg and empty-filter calls return [object Array].
 *
 * NON-ASSERTABLE: non-empty tracking row field shape after a real send.
 * EXPECTED OUTPUT: every line starts with PASS.
 */

function assert(id, actual, expected) {
    Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}

var ts = TriggeredSend.Init("ssjs-triggeredsend");
assert("typeof Tracking.Retrieve is function", typeof ts.Tracking.Retrieve, "function");
var rows = ts.Tracking.Retrieve();
assert("Tracking.Retrieve() reports as [object Array]", Object.prototype.toString.call(rows), "[object Array]");
assert("Tracking.Retrieve() length >= 0", (rows && rows.length >= 0) ? "true" : "false", "true");
var filtered = ts.Tracking.Retrieve({ Property: "SendID", SimpleOperator: "equals", Value: 999999991 });
assert("filtered Tracking.Retrieve reports as [object Array]", Object.prototype.toString.call(filtered), "[object Array]");
assert("filtered empty length is 0", "" + filtered.length, "0");
</script>


<TriggeredSendInstance>.Tracking.Clicks.Retrieve

Returns click tracking information for the previously initialized triggered send definition.

Syntax

<TriggeredSendInstance>.Tracking.Clicks.Retrieve(filter)

Parameters

Name Type Required Description
filter object Yes WSProxy-style filter restricting click results

Return value

object[]

Examples

Platform.Load("core", "1.1.5");
var tsd = TriggeredSend.Init("MyTSDKey");
var results = tsd.Tracking.Clicks.Retrieve({ Property: "SendUrlID", SimpleOperator: "equals", Value: 12345 });
Show test script
<script runat="server">
Platform.Load("core", "1.1.5");

/*
 * Chapter: <TriggeredSendInstance>.Tracking.Clicks.Retrieve(filter)
 *
 * CloudPage GET context. Proves:
 *   1. Tracking.Clicks.Retrieve is a function requiring a filter.
 *   2. Empty match returns [object Array] length 0 (page example shape).
 *
 * EXPECTED OUTPUT: every line starts with PASS.
 */

function assert(id, actual, expected) {
    Platform.Response.Write((actual === expected ? "PASS " : "FAIL ") + id + " -> [" + actual + "]\n");
}

var ts = TriggeredSend.Init("ssjs-triggeredsend");
assert("typeof Tracking.Clicks.Retrieve is function", typeof ts.Tracking.Clicks.Retrieve, "function");
var rows = ts.Tracking.Clicks.Retrieve({ Property: "SendUrlID", SimpleOperator: "equals", Value: 999999991 });
assert("empty Clicks.Retrieve reports as [object Array]", Object.prototype.toString.call(rows), "[object Array]");
assert("empty Clicks.Retrieve length is 0", "" + rows.length, "0");
</script>


<TriggeredSendInstance>.Tracking.TotalByInterval.Retrieve

Returns aggregated tracking data for the previously initialized triggered send. Aggregates by type over the date range, grouped by groupBy.

Syntax

<TriggeredSendInstance>.Tracking.TotalByInterval.Retrieve(type, startDate, endDate, groupBy)

Parameters

Name Type Required Description
type string Yes Type of data: "Send", "Open", "Click", "Bounce", "Unsubscribe"
startDate string | Date Yes Start date of the data period (MM-DD-YYYY string or Date)
endDate string | Date Yes End date of the data period (MM-DD-YYYY string or Date)
groupBy string Yes Interval used to aggregate: "day" or "hour"

Return value

object[]

Examples

Platform.Load("core", "1.1.5");
var tsd = TriggeredSend.Init("MyTSDKey");
var results = tsd.Tracking.TotalByInterval.Retrieve("Click", "07-01-2010", "07-31-2010", "day");
Show test script
<script runat="server">
Platform.Load("core", "1.1.5");

/*
 * Chapter: <TriggeredSendInstance>.Tracking.TotalByInterval.Retrieve(...)
 *
 * CloudPage GET context. Proves:
 *   1. TotalByInterval.Retrieve is a function.
 *   2. Page example shape (type/start/end/groupBy strings) returns
 *      [object Array] with length > 0 for a wide historical window.
 *   3. startDate/endDate also accept Date values (same length as the
 *      string-date call for an identical window) — type-acceptance.
 *   4. groupBy "hour" is accepted.
 *
 * 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"; }
}

var ts = TriggeredSend.Init("ssjs-triggeredsend");
assert("typeof TotalByInterval.Retrieve is function", typeof ts.Tracking.TotalByInterval.Retrieve, "function");

var byString = null;
assert("string dates do not throw", invocationResult(function () {
    byString = ts.Tracking.TotalByInterval.Retrieve("Click", "07-01-2010", "07-31-2010", "day");
}), "returned");
assert("string dates result reports as [object Array]", Object.prototype.toString.call(byString), "[object Array]");
assert("string dates result length > 0", (byString && byString.length > 0) ? "true" : "false", "true");

var byDate = null;
assert("Date dates do not throw", invocationResult(function () {
    byDate = ts.Tracking.TotalByInterval.Retrieve("Click", new Date(2010, 6, 1), new Date(2010, 6, 31), "day");
}), "returned");
assert("Date dates result reports as [object Array]", Object.prototype.toString.call(byDate), "[object Array]");
assert("Date dates length matches string dates", "" + byDate.length, "" + byString.length);

var byHour = ts.Tracking.TotalByInterval.Retrieve("Open", "07-01-2010", "07-31-2010", "hour");
assert("groupBy hour returns [object Array]", Object.prototype.toString.call(byHour), "[object Array]");
assert("groupBy hour length > 0", (byHour && byHour.length > 0) ? "true" : "false", "true");
</script>

See Also

See Also