Trigger scripts writing and testing
Triggers are custom actions you can configure when a message is received or changes state. This page details how to write and test trigger scripts.
Triggers are a part of the Auron SMS Server message bus. You can find more information on how to configure triggers here.
This page describes:
- The basics of triggers;
- How to write a JavaScript or VBScript trigger;
- Include files;
- Logging debug output;
- Creating new messages (SMS or E-mail);
- Opening and creating files;
- Calling external HTTP API’s;
- Connecting to an external database;
- Opening a MS Excel sheet;
- How to write a SQL Script trigger;
- Testing your trigger.
Trigger basics
A trigger has these main parts:
- The message type. The trigger only applies to messages of this type;
- On status. The trigger runs when a message reaches this status;
- A condition. A SQL expression that must be true for the trigger to run;
- The trigger script. This is the script that runs when the condition is true.
The trigger script must be either:
- VBScript;
- JavaScript;
- SQL Script.
For most cases there’s a trigger template available. If there’s no trigger template you can either create a new trigger or create one from a template to customize it.
Trigger scripts always run in sequence according to the processing order of all triggers.
Writing a JavaScript or VBScript trigger
JavaScript and VBScript (Visual Basic Script) triggers are similar in that they both run using the Microsoft Active Scripting engine. This means that in-spite of having a different syntax they have roughly the same abilities.
You can learn more about JavaScript and VBScript in general on W3Schools.
An empty trigger script always has the same structure:
STR_DEBUGFILE = "C:\ProgramData\Auron\Log\TriggerName.txt"
B_ENABLE_DEBUG = true
// ========================================================================
// Function: ProcessMessageEx
// ------------------------------------------------------------------------
// ProcessMessageEx trigger function to process incoming messages
// ========================================================================
function ProcessMessageEx(objMessageIn, objMessageDB, dctContext)
{
Log(">> ProcessMessageEx")
// ... Your logic here
Log("<< ProcessMessageEx")
}
CONST STR_DEBUGFILE = "C:\ProgramData\Auron\Log\TriggerName.txt"
CONST B_ENABLE_DEBUG = True
' // ========================================================================
' // Function: ProcessMessageEx
' // ------------------------------------------------------------------------
' // ProcessMessageEx trigger function to process incoming messages
' // ========================================================================
Function ProcessMessageEx(objMessageIn, objMessageDB, dctContext)
Log ">> ProcessMessageEx"
' ... Your logic here
Log "<< ProcessMessageEx"
End Function
The top two lines declare if logging (debug) is enabled as well as the location of the log file.
The service calls ProcessMessageEx for each message that matches the trigger condition.
You can use the top of the trigger script to initialize variables that you’re going to reuse in ProcessMessageEx for each message.
The arguments to ProcessMessageEx are:
- objMessageIn. This is the message object that triggered this trigger. Which specific message object depends on the trigger message type. They are listed below;
- objMessageDB. This is an instance of MessageDB. This object gives access to the message database so you can create new messages or run queries against it;
- dctContext. This is simply a dictionary object that you can use for keeping variables between different calls to ProcessMessageEx. You can also keep variables between calls to ProcessMessageEx in the global scope of the script.
The objMessageIn is always of type:
- SmsMessage When the trigger message type is SMS;
- EmailMessage When the trigger message type is E-mail;
- FileMessage When the trigger message type is File;
- SmppServerBindMessage When the trigger message type is an SMPP Server Bind;
- Message If the trigger message type is unknown (custom).
The trigger script reloads and re-initializes when:
- The Auron SMS Server service starts;
- The trigger script or the trigger configuration is modified.
Include files
You can add a number of include files to your trigger. By default there’s always the ‘common’ include file (‘common.vbs’ or ‘common.js’) that defines the log function but you can add your own as well.
If you’ve made modifications to the ‘common’ include file the setup won’t replace it on an update.
The list of include files is appended to the trigger script in memory right before running the script when starting the service. In case of an error the line numbers are corrected in the error message.
Logging debug output
Use the Log function to log information to a debug file. The two constants at the top of the script file determine the logging behavior:
- STR_DEBUGFILE Contains the log file destination path;
- B_ENABLE_DEBUG Set this to false to disable logging.
Creating new messages (SMS or E-mail)
Create a new SMS or E-mail message directly from a trigger by using the local API.
Any of the Local API object can be freely used in trigger scripts.
How to create a new SMS:
// ProcessMessageEx delivers an instance of objMessageDB that already
// has a connection. Using that instance performs better than creating
// a new instance.
//
// objMessageDB = new ActiveXObject("AxMmServer.MessageDB")
objSms = objMessageDB.Create("SMS")
objSms.ToAddress = "+31611223344"
objSms.Body = "Hello, World!"
objSms.ChannelID = "" // Specify a channel or depend on the router
objMessageDB.Save(objSms)
' ProcessMessageEx delivers an instance of objMessageDB that already
' has a connection. Using that instance performs better than creating
' a new instance.
'
' Set objMessageDB = CreateObject("AxMmServer.MessageDB")
Set objSms = objMessageDB.Create("SMS")
objSms.ToAddress = "+31611223344"
objSms.Body = "Hello, World!"
objSms.ChannelID = "" ' Specify a channel or depend on the router
objMessageDB.Save(objSms)
How to create a new E-mail:
// ProcessMessageEx delivers an instance of objMessageDB that already
// has a connection. Using that instance performs better than creating
// a new instance.
//
// objMessageDB = new ActiveXObject("AxMmServer.MessageDB")
objEmail = objMessageDB.Create("EMAIL")
objEmail.ToAddress = "alerting@company.com"
objEmail.BodyPlainText = "Hello, World!"
objEmail.ChannelID = "" // Specify a channel or depend on the router
objMessageDB.Save(objEmail)
' ProcessMessageEx delivers an instance of objMessageDB that already
' has a connection. Using that instance performs better than creating
' a new instance.
'
' Set objMessageDB = CreateObject("AxMmServer.MessageDB")
Set objEmail = objMessageDB.Create("EMAIL")
objEmail.ToAddress = "alerting@company.com"
objEmail.BodyPlainText = "Hello, World!"
objEmail.ChannelID = "" ' Specify a channel or depend on the router
objMessageDB.Save(objEmail)
Opening and creating files
For file access you can use the Scripting.FileSystemObject. This is a default part of Windows.
To write a string to file:
objFso = new ActiveXObject("Scripting.FileSystemObject")
// Arguments are: File path, Overwrite?, Unicode?
objFile = objFso.CreateTextFile("test.txt", true, true)
objFile.WriteLine("This is surprisingly easy ?")
objFile.Close()
Set objFso = CreateObject("Scripting.FileSystemObject")
' Arguments are: File path, Overwrite?, Unicode?
Set objFile = objFso.CreateTextFile("test.txt", True, True)
objFile.WriteLine "This is surprisingly easy ?"
objFile.Close
If you want to read a file into a string without using the file channel:
objFso = new ActiveXObject("Scripting.FileSystemObject")
// Arguments are: File path, IoMode, Create?, Format
// IoMode: 1=Read, 2=Write, 8=Append
// Format: -2=Default, -1=Unicode, 0=ASCII
objFile = objFso.OpenTextFile("test.txt", 1, false, -1)
sText = objFile.ReadAll()
Set objFso = CreateObject("Scripting.FileSystemObject")
' Arguments are: File path, IoMode, Create?, Format
' IoMode: 1=Read, 2=Write, 8=Append
' Format: -2=Default, -1=Unicode, 0=ASCII
Set objFile = objFso.OpenTextFile("test.txt", 1, False, -1)
sText = objFile.ReadAll()
Calling external HTTP API’s
Use the well known Windows HTTPXML API for making HTTP API calls.
An example of a simple HTTP GET request:
objHttp = new ActiveXObject("MSXML2.ServerXMLHTTP")
// arguments are: Verb, Url, Async, (opt)User, (opt)Password
objHttp.open("GET", "https://www.auronsoftware.com/fortune/", false)
objHttp.send()
sResult = objHttp.responseText
Set objHttp = CreateObject("MSXML2.ServerXMLHTTP")
' arguments are: Verb, Url, Async, (opt)User, (opt)Password
objHttp.open "GET", "https://www.auronsoftware.com/fortune/", false
objHttp.send()
sResult = objHttp.responseText
An example of a more elaborate POST request with authorization header:
objHttp = new ActiveXObject("MSXML2.ServerXMLHTTP")
// arguments are: Verb, Url, Async, (opt)User, (opt)Password
objHttp.open("POST", "https://www.auronsoftware.com/fortune/", false)
objHttp.setRequestHeader("Content-Type", "application/json")
objHttp.setRequestHeader("Authorization", "{BEARER TOKEN}")
objHttp.send("{\"json\": \"values\"}")
sResult = objHttp.responseText
Set objHttp = CreateObject("MSXML2.ServerXMLHTTP")
' arguments are: Verb, Url, Async, (opt)User, (opt)Password
objHttp.open "POST", "https://www.auronsoftware.com/fortune/", false
objHttp.setRequestHeader "Content-Type", "application/json"
objHttp.setRequestHeader "Authorization", "{BEARER TOKEN}"
objHttp.send("{""json"": ""values""}")
sResult = objHttp.responseText
If your API uses OAuth2 you can authorize using the OAuth2 Authorizer and use the OAuth2 API to refresh your bearer token when/if required.
Connecting to an external database
Use the Windows ADODB objects to connect to an external database from your trigger.
For example to handle an unsubscribe message you could do this:
objDatabase = new ActiveXObject("ADODB.Connection")
// The ADO connection string for your external database
sCs = "Provider=Microsoft.Ace.OLEDB.12.0;Data Source=students.mdb"
objDatabase.Open(sCs)
// Parameterized update; better resistance against malicious input
// Say this is an incoming unsubscribe message and we're updating the database
// The e-mail address to update would be the FromAdress from the objMessageIn
// provided by the ProcessMessageEx function
sFromEmail = "alice@school.com" // objMessageIn.FromAddress
objCmd = new ActiveXObject("ADODB.Command")
objCmd.ActiveConnection = objDatabase
// Arguments are: Name, Type, Direction, Size
// Find type values here:
// https://docs.microsoft.com/en-us/sql/ado/reference/ado-api/datatypeenum
// Find direction values here:
// https://docs.microsoft.com/en-us/sql/ado/reference/ado-api/parameterdirectionenum
objParam = objCmd.CreateParameter("@eml", 200, 1, 255, sFromEmail)
objCmd.Parameters.Append(objParam)
objCmd.CommandText = "UPDATE Students SET Subscribed = 0 WHERE Email = @eml"
objCmd.Execute()
objDatabase.Close()
Set objDatabase = CreateObject("ADODB.Connection")
' The ADO connection string for your external database
sCs = "Provider=Microsoft.Ace.OLEDB.12.0;Data Source=students.mdb"
objDatabase.Open sCs
' Parameterized update; better resistance against malicious input
' Say this is an incoming unsubscribe message and we're updating the database
' The e-mail address to update would be the FromAdress from the objMessageIn
' provided by the ProcessMessageEx function
sFromEmail = "alice@school.com" 'objMessageIn.FromAddress
Set objCmd = CreateObject("ADODB.Command")
objCmd.ActiveConnection = objDatabase
' Arguments are: Name, Type, Direction, Size
' Find type values here:
' https://docs.microsoft.com/en-us/sql/ado/reference/ado-api/datatypeenum
' Find direction values here:
' https://docs.microsoft.com/en-us/sql/ado/reference/ado-api/parameterdirectionenum
Set objParam = objCmd.CreateParameter("@eml", 200, 1, 255, sFromEmail)
objCmd.Parameters.Append(objParam)
objCmd.CommandText = "UPDATE Students SET Subscribed = 0 WHERE Email = @eml"
objCmd.Execute()
objDatabase.Close
Or use something like this if you just need to select a value from your database:
objDatabase = new ActiveXObject("ADODB.Connection")
// The ADO connection string for your external database
sCs = "Provider=Microsoft.Ace.OLEDB.12.0;Data Source=students.mdb"
objDatabase.Open(sCs)
sName = ""
sQ = "SELECT Name FROM Students WHERE Email = 'alice@school.com'"
objRs = objDatabase.Execute(sQ)
if (!objRs.EOF)
{
sName = objRs("Name").Value
}
// sName is now the name of the student
objDatabase.Close()
Set objDatabase = CreateObject("ADODB.Connection")
' The ADO connection string for your external database
sCs = "Provider=Microsoft.Ace.OLEDB.12.0;Data Source=students.mdb"
objDatabase.Open sCs
sName = ""
sQ = "SELECT Name FROM Students WHERE Email = 'alice@school.com'"
Set objRs = objDatabase.Execute(sQ)
If Not objRs.EOF Then
sName = objRs("Name").Value
End If
' sName is now the name of the student
objDatabase.Close
Opening a MS Excel sheet
Excel sheets works exactly like a database by using the Windows ADODB objects. When your tables have names you can just select from them and update them.
This is an example of how to handle an unsubscribe if you table was in excel instead of a database:
objCon = new ActiveXObject("ADODB.Connection")
objCon.Open("Provider=Microsoft.ACE.OLEDB.12.0; Data Source=Students.xls;" +
" Extended Properties='Excel 12.0 Xml; HDR=YES'")
// Parameterized update; better resistance against malicious input
// Say this is an incoming unsubscribe message and we're updating the database
// The phone numbers to update would be the FromAdress from the objMessageIn
// provided by the ProcessMessageEx function
sFromNumber = "+31612345678" // objMessageIn.FromAddress
objCmd = new ActiveXObject("ADODB.Command")
objCmd.ActiveConnection = objCon
// Arguments are: Name, Type, Direction, Size
// Find type values here:
// https://docs.microsoft.com/en-us/sql/ado/reference/ado-api/datatypeenum
// Find direction values here:
// https://docs.microsoft.com/en-us/sql/ado/reference/ado-api/parameterdirectionenum
objParam = objCmd.CreateParameter("@nr", 200, 1, -1, sFromNumber)
objCmd.Parameters.Append(objParam)
objCmd.CommandText = "UPDATE Students SET Subscribed = 1 WHERE [Phone nr] = @nr"
objCmd.Execute()
objCon.Close()
Set objCon = CreateObject("ADODB.Connection")
objCon.Open "Provider=Microsoft.ACE.OLEDB.12.0; Data Source=Students.xls;" & _
" Extended Properties='Excel 12.0 Xml; HDR=YES'"
' Parameterized update; better resistance against malicious input
' Say this is an incoming unsubscribe message and we're updating the database
' The phone number to update would be the FromAdress from the objMessageIn
' provided by the ProcessMessageEx function
sFromNumber = "+31612345678" 'objMessageIn.FromAddress
Set objCmd = CreateObject("ADODB.Command")
objCmd.ActiveConnection = objCon
' Arguments are: Name, Type, Direction, Size
' Find type values here:
' https://docs.microsoft.com/en-us/sql/ado/reference/ado-api/datatypeenum
' Find direction values here:
' https://docs.microsoft.com/en-us/sql/ado/reference/ado-api/parameterdirectionenum
Set objParam = objCmd.CreateParameter("@nr", 200, 1, -1, sFromNumber)
objCmd.Parameters.Append(objParam)
objCmd.CommandText = "UPDATE Students SET Subscribed = 1 WHERE [Phone nr] = @nr"
objCmd.Execute()
objCon.Close
Or use something like this if you just need to select a value from your Excel sheet:
objCon = new ActiveXObject("ADODB.Connection")
objCon.Open("Provider=Microsoft.ACE.OLEDB.12.0; Data Source=Students.xls;" +
" Extended Properties='Excel 12.0 Xml; HDR=YES'")
// Use brackets [] if a fiel or table name has spaces or special characters
q = "SELECT Name FROM Students WHERE [Phone nr] = '+31687654321'"
objRs = objCon.Execute(q)
sName = ""
if (!objRs.EOF)
{
sName = objRs("Name").Value
}
// sName holds the name of the student
objCon.Close()
Set objCon = CreateObject("ADODB.Connection")
objCon.Open "Provider=Microsoft.ACE.OLEDB.12.0; Data Source=Students.xls;" & _
" Extended Properties='Excel 12.0 Xml; HDR=YES'"
' Use brackets [] if a fiel or table name has spaces or special characters
q = "SELECT Name FROM Students WHERE [Phone nr] = '+31687654321'"
Set objRs = objCon.Execute(q)
sName = ""
If Not objRs.EOF Then
sName = objRs("Name").Value
End If
' sName holds the name of the student
objCon.Close
Writing a SQL trigger script
The SMS Server already has a database connection open and therefore is able to optimize the execution of a SQL script to a great extend.
There’s no structure to a SQL trigger script as there is to JavaScript or VBScript triggers.
It can be a multi-line script, a single update or insert statement or a stored procedure call.
You can use any of the message variables in your trigger script by using the field name prefixed with ‘@fld’.
For example, this can be a SQL trigger script that handles an unsubscribe message:
-- @fldFromAddress is set by the SMS Server service to the value of 'FromAddress'
-- As an additional optimization the SMS Server only initializes values that you
-- actually reference in the SQL script.
UPDATE dbStudents.dbo.tblStudents SET subscribed = 0 WHERE EmailAddress = @fldFromAddress
Another example forwards an incoming SMS to an e-mail message using the ‘InsertEmail‘ view:
INSERT INTO InsertEmail(StatusID, ToAddress, Subject, BodyPlainText) VALUES
("SCHEDULED", "alert@yourcompany.com", "SMS from: " + @fldFromAddress, @fldBody)
Testing your triggers
With the SMS Server it’s easy to test your triggers. The following sections describe some of the tools you can use.
The trigger activity view
Triggers automatically reload after you modify either the definition or the script file itself.
For JavaScript and VBScript triggers this means a basic syntax check every time you hit ‘ctrl-s’ in your editor.
Therefore it makes sense to keep an eye on the trigger activity view while you’re editing your script.
Create incoming messages and reprocess them
You don’t need to spend credits to test your trigger. You can simply create an incoming message and reprocess it until your trigger works.
Find out how to create message from the manager application here. Make sure you select ‘In’ as your direction and click ‘Create’.
This causes triggers on incoming SMS messages to run on this message.
To continue testing with this same message just right-click on the message and select ‘Reprocess’. Reprocess clears the processed status and causes triggers to run again for this message.
If you’re testing different states that ‘Received’ you can create a message and modify its state in much the same way. Just right-click the message, select ‘Update message status’ and select the status you need to test.
The message trace tab
Every message keeps its own history in the ‘Trace’ field of the message. This is extremely useful when writing or testing scripts.
The message trace shows the trigger status and which triggers ran on this message. If there was an error it shows the details of the error. Every message type always has this trace tab.
You can add custom trace messages from your trigger by calling the ‘AddTrace‘ method on a message.
The trigger log file
JavaScript and VBScript triggers have the option to keep a log file. The full path of which is at the top of the trigger file.