Contents: [hide]

Overview

Notifications can be used to keep users apprised of new cases in their inbox and notify them at specified times while running cases. In ProcessMaker, all notifications are sent to users via email, which is why it is important to enter a valid email address for each user and properly configure ProcessMaker to connect to an email server to sent out notifications.

There are three types of notifications:

The subject line and body of these email notifications can be customized, and system variables and case variables can be inserted to personalize the email for the recipient using data from the current case.

The content of Task Notifications is in plain text, which is defined in the Task Properties. In contrast, the content of Message Events and Trigger Messages is specified inside a template file, which permits the use of HTML formatting. The template file can be created using ProcessMaker's template editor or uploaded after being created in an external HTML editor, such as FrontPage, DreamWeaver or BlueGriffon.

Note: Emails are sent to the configured email server when cron.php is executed, so the ProcessMaker server needs to be configured to execute a cron job in Linux/UNIX or a Scheduled Task in Windows.

Task Notifications

Note: Take into consideration that in cases where the next task of the process routes to a sub-process, the case number in the Task Notifications will be the case number of the master process.

Task Notifications are useful for keeping users apprised when they have been assigned to work on a task in a case.

To create a message to be sent to an assigned user, go to the Designer menu and open a process for editing. In the process map, right click on the task that should send out notifications when users are assigned to work on the task when running cases. In the dropdown menu that appears, select the Properties option.

Go to the Notifications tab and select to notify either the assigned user of the current task or the next user.

  • After routing notify the next assigned user(s): This option was included in previous ProcessMaker versions; the process locates the next task and sends the notification to the assigned user.

  • Notify the assigned user to this task: The process will send the notification to the assigned user of the current task when the configured task is assigned to them. This option is useful when the process design has script tasks, loops or gateways and it is difficult to determine the next assigned user. Notice that when this option is configured in the first task of a process, the notification will not be sent unless there is a loop returning to the first task.

Note that both checkboxes can be selected. In that case, two notifications will be sent in different moments.

Next, define the content of the notification:

  • Email Account: Displays all the email accounts configured in the Email Servers section under the Settings tab and the "Default Email Account" option. Notifications will be sent using the selected email account.

  • Email from Format: Displays the options "Assigned User" and "Email Account Settings".

    • Assigned User: This option sends the email notification to the email account selected in the Email Account field using the name of the user who completed the previous task in the title of the email.
    • Email Account Settings: This option sends the email notification using the Sender Email and Sender Name values defined in the email server configuration of the email selected in the Email Account field.

      Note that some mail servers don't allow the Sender Email value to be different from the Sender Account (real email account). In this case, the notification will be sent using the email account selected in the Email Account field.

  • Subject: The subject of the email message. System variables and case variables can be used in the subject of the email message by clicking the @@ button.

  • Content Type:
    • For a simple message without formatting, choose the Plain Text option. Enter text into the Message box. Case variables can be inserted too.
    • For more control over the formatting, select the HTML Template option. Then, select the name of the template file to be used for the body of the email message. To create template files, see Templates.

When done defining the Task Notification, click on Save.

Note: A Task Notification cannot be sent to a Script Task because it doesn't have an assigned user, which is required for a Task Notification to be sent.

Inserting Variables

To insert a variable into the email, click on the [@@] button and select the variable to insert. @@variable will insert the variable enclosed in double quotation marks, whereas @#variable inserts the variable without quotation marks. Make sure that all variables used in the message have already been created at some earlier point in the process. System variables (such as @@USR_USERNAME and @@APPLICATION) are automatically created and case variables are created in Dynaform fields or defined in triggers.

When a field in a Dynaform is submitted, ProcessMaker stores both a @@variable and @@variable_label for the field, and either variable can be used in the email template. @@variable is the value that is stored internally by ProcessMaker and @@variable_label is the text displayed to the user:

  • For textboxes and textareas, there is no difference between @@variable and @@variable_label.
  • For dropdown boxes and radio buttons, the value of @@variable is the value/key of the selected option and @@variable_label is the displayed text of the selected option. These are defined either in the field's options property or by the first and second fields returned by the sql query.
  • A checkbox (which is not in a grid) has a value of ["1"] if marked or ["0"] if unmarked, so it can't be used directly in a template because it is an array. Instead, use @@variable_label, which by default is "true" if marked and "false" if unmarked; however, these values can be changed. If a checkbox is inside a grid, then its @@variable is set to "1" if marked or "0" if unmarked, which are strings that can be used in templates.
  • For datetime fields, @@variable is the datetime in "YYYY-MM-DD HH:MM:SS" format, such as "2016-02-25 16:03:59". In contrast, @@variable_label is the datetime configured by the field's format property. For example, if the format is "MMMM Do, YYYY", then it would be "February 2nd, 2016".
  • For checkgroup fields, @@variable is ["option1", "option2", ...], such as ["accounting","landscaping","cleaning"], which is an array and therefore cannot be inserted into templates. Instead, use @@variable_label, which is a string in the form "["Option 1","Option 2",...]", such as "["Accounting","Landscaping","Cleaning and janitorial"]".
    Note: For prettier formatting, create a string variable and a trigger that is executed beforehand that stores the selected options in separate lines in the string variable. The json_decode() function can be used to convert @@variable_label into an array. For example, the following trigger can be used for a checkgroup whose variable is named "selectServices":
    @@selectServicesFormatted = '';
    $aOptions = json_decode(@@selectServices_label);
    foreach ($aOptions as $option) {
        @@selectServicesFormatted .= $option . "<br>\n";
    }
    Then, insert @#selectServicesFormatted into the template.
  • For file fields, @@variable_label has the fil ename of the selected file in a JSON array, such as "["employeePhoto.jpg"]" or "[]" if no file was selected. In version 3.0.1.8 and later, @@variable is "["file-uid"]", such as "["file-uid"]", "["263247890574cd24044f980079517567"]" or "[]" if there is no selected file.
    Note: To select the file name without the enclosing brackets, create a string variable and a trigger that is executed beforehand that stores the filename in the string variable. The json_decode() function can be used to convert @@variable_label into an array. For example, the following trigger can be used for a file field whose variable is named "invoiceFile":
    @@invoiceFilename = '';
    $aFilenames = json_decode(@@invoiceFile_label);
    if (count($aFilenames) > 0) {
        @@invoiceFilename = $aFilenames[0];
    }
    Then, insert @#invoiceFilename into the template.
  • For grids, there is no @@variable_label variable. See below.

Note: If a case variable doesn't exist, the message will be sent out with the name of the variable in the text. Case variables will not be created if a DynaForm is not submitted, or the process has a condition that evaluates to false so the DynaForm is skipped in the case. To avoid variable names appearing in messages, fire a trigger after the Dynaform to check whether the variable has been set. If not, set the variable to an empty string, so that any subsequent notifications will insert a blank space in place of the variable name:

if (!isset(@@someVariable)) {  
   @@someVariable = "";
}

Message Events

Message events can be used to send out messages at specified times. For more information, see Events.

Trigger Messages

Email notifications can be sent out in triggers using the PMFSendMessage() function. Sending out messages in Triggers provides a great deal of flexibility, since the parameters for the PMFSendMessage() function allow the sender, the list of recipients, the subject line, the template file and even customized insertion variables to be specified. In addition, the message can be sent based on the conditions of the particular case, and a condition can be set for the firing of the trigger, or the PMFSendMessage() function can be wrapped inside an if clause in the trigger code.

To configure the notification, the following steps are necessary:

  1. Create the HTML email template
  2. Create a trigger containing the PMFSendMessage() function
  3. Assign the trigger to a step in the process.

Create the HTML Email Template

Email template files can be created inside ProcessMaker with the WYSIWYG editor in the Templates option in the Main Toolbox. For greater creativity, create the template file with an external plain text editor or HTML editor and then upload it to ProcessMaker.

Open a process for editing. Click on the Template option in the main toolbox.

Then click on either the Create or Upload links to create or upload the template file.

The template file will determine the body of the email message. This text can contain system and case variables and HTML tags. For more information on the format of template files, see Output Documents. For example, the following template is used when a leave request is approved: Dear @#reqUserName,
Your leave request has been approved. Please find details below:
Date From: @#fromReq Date To: @#toReq Days Requested: @#daysReq
Once your leave period has ended, please do not forget to fill out a Leave Report upon returning.
Regards,   @#reqSupervisor

Its HTML code can be edited by clicking on the button in the editor to see the following HTML code:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
</head>
<body>
<p>Dear @#reqUserName, <br>
Your leave request has been approved.  Please find details below: <br>
 <b>Date From:</b>      @#fromReq <br>
 <b>Date To:</b>        @#toReq   <br>
 <b>Days Requested:</b> @#daysReq <br>
<br>
Once your leave period has ended, please do not forget to fill out a Leave Report upon returning. <br><br>
Regards, <br>
 &nbsp; @#reqSupervisor</p>
</body>
</html>

Links to Cases in Templates

The email template can also contain links to access resources inside ProcessMaker. To learn more about web browser redirection inside ProcessMaker, see JavaScript Frames, the G::header() function and the Link field.

An email template can include a link to open a case with a click of the mouse. Links to the current case can be constructed using system variables. For example, to open a link to the current case:

Dear @#reqUserName,

Your leave request has not yet been approved. Please find the details below:
Date From: @#fromReq Date To: @#toReq Days Requested: @#daysReq
We need you to fill in some details. Please click the link below:
http://example.com/sys@#SYS_SYS/@#SYS_LANG/@#SYS_SKIN/cases/open?APP_UID=@#APPLICATION&DEL_INDEX=@#INDEX&action=draft

Regards,   @#reqSupervisor

Its HTML code can be edited by clicking on the button in the editor to see the following HTML code:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
</head>
<body>
<p>Dear @#reqUserName, <br>
Your leave request has been approved.  Please find details below:</p>
<table>
<tr><td><b>Date From:</b>     </td><td>@#fromReq</td></tr>
<tr><td><b>Date To:</b>       </td><td>@#toReq  </td></tr>
<tr><td><b>Days Requested:</b></td><td>@#daysReq</td></tr>
</table>
<p>We need you to fill in some details. Please click the link below:<br>
<a href="http://example.com/sys@#SYS_SYS/@#SYS_LANG/@#SYS_SKIN/cases/open?APP_UID=@#APPLICATION&DEL_INDEX=@#INDEX&action=draft">http://example.com/sys@#SYS_SYS/@#SYS_LANG/@#SYS_SKIN/cases/open?APP_UID=@#APPLICATION&amp;DEL_INDEX=@#INDEX&amp;action=draft</a></p>

<p>Regards, <br>
 &nbsp; @#reqSupervisor</p>
</body>
</html>

Remember that the person receiving the email needs to either be assigned to work on the current task in the case or have process permissions to open the case. If opening a case as a Process Supervisor, a different URL can be used:
http://example.com/sys@#SYS_SYS/@#SYS_LANG/@#SYS_SKIN/cases/open?APP_UID=@#APPLICATION&DEL_INDEX=@#INDEX&to_revise=true&action=to_revise

If the case is completed, paused or canceled, or the user doesn't have rights to open the case, then the summary for the case will be displayed. The summary can also be displayed by setting action=sent; it is not necessary to include the delegation index number in the URL:
http://example.com/sys@#SYS_SYS/@#SYS_LANG/@#SYS_SKIN/cases/open?APP_UID=@#APPLICATION&action=sent

If the user doesn't currently have an active login session in ProcessMaker, the web browser will first redirect to the login page and then redirect to the specified case after logging in. If the case is opened in a task that has already been completed, then the web browser will redirect to the list of cases in the inbox.

Redirecting to the ../cases/main Page

Unfortunately, the page "cases/open?..." is designed to open a case inside an <iframe> below the main menu bar, so redirecting the web browser to this address will open a window that doesn't have the main menu bar and the Home sidebar. To be able to get back to the principal page after completing the task, it is recommended to add the following trigger to the process that redirects the web browser back to the "../cases/main" page:

echo "<script>top.location.href = '../cases/main';</script>";

Set the above trigger to execute after routing in the task specified by the "cases/open?..." page. When the user completes working on the task and clicks on the Continue button at the end of the task, the web browser will automatically be redirected to the "../cases/main" page, which displays the top-level menu, the Home sidebar and the list of cases in the inbox.

If the user needs to be able to immediately return to the "../cases/main" page, a button that redirects to that page can be added to the Dynaform.

For example, if a button is added with the ID "goToInbox", then the following JavaScript code can be added to the Dynaform to save the contents of the Dynaform and redirect the web browser:

$("#goToInbox").click( function() {
   $("form").saveForm();
   top.location.href = "../cases/main";
});

Grids in Templates

The email template can also contain grid data. For example, the grid can be placed inside an HTML table:

Dear @#reqUserName, Your leave request has been approved. Please find details below:
Date FromDate ToNumber DaysComment
@#detDateFrom@#detDateTo@#detNoDays@#detComment
Once your leave period has ended, please do not forget to fill out a Leave Report upon returning.
Regards,   @#reqSupervisor

Its HTML code would be:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
</head>
<body>
Dear @#reqUserName, <br>
Your leave request has been approved.  Please find details below: <br>
<table>
<tr><th>Date From</th><th>Date To</th><th>Number Days</th><th>Comment</th></tr>
<!-- @>reqLeaveGrid -->
<tr><td>@#detDateFrom</td><td>@#detDateTo</td><td>@#detNoDays</td><td>@#detComment</td></tr>
<!-- @<reqLeaveGrid -->
</table>
<p>Once your leave period has ended, please do not forget to fill out a Leave Report upon returning. <br><br>
Regards, <br>
 &nbsp;  @#reqSupervisor</p>
</body>
</html>

For each row in the grid between @>reqLeaveGrid and @<reqLeaveGrid, the grid fields @#detDateFrom, @#detDateTo, @#detNoDays, and @#detComment will be repeated on a new line. For more information on inserting grids into templates, see Grids in Output Documents.

Moreover, it is possible to introduce images inside the template by editing the HTML code. For example:

<img src="http://example.com/companyLogo.jpg">

Images inserted in email templates should be hosted in a server with public access, otherwise they might not be viewable by the person receiving the email. For example, the corporate logo placed in the location INSTALL-DIRECTORY/workflow/public_html/companyLogo.jpg on the ProcessMaker server is publicly accessible at the address: http://example.com/companyLogo.jpg

Sending Emails with PMFSendMessage()

The PMFSendMessage()function is used to send out customized email notifications based on a template file. To use this function, create a Trigger and add this function to the code for that trigger. For more information and code examples, see the documentation for the PMFSendMessage() function. Also see the code examples below.

To find which users are assigned to cases, tasks, groups, departments, roles, etc., it is often necessary to use lookup information in the database using the executeQuery() function. Then, the email address of those users can be found with the userInfo() function. Emails can be sent to multiple recipients with the PMFSendMessage() function by separating the email addresses with commas (,) in the $to, $cc or $bcc parameters.

Assigning the Trigger to Step(s)

Once you have uploaded your template email file and defined a trigger to send the email, it is possible to assign the related trigger to steps in different instances:

  • Before/after a step (DynaForm, Input Document or Output Document) is displayed.
  • Before the case assigns a user to the next task in the case.
  • Before/after a case is routed to the next task in the case.

In each instance, it is also possible to define conditions that dictate whether a trigger should be executed or not. If the condition evaluates to false, the trigger will not be fired. If it evaluates to true, the trigger will be fired.

For example, the following condition defines that the trigger will be executed only if the @@repFinalDec case variable is 0. In other words, the notification will be sent only when this condition is true.

Trigger Message Examples

Emailing the Current Assigned User of a Case

A message can be sent to the user currently assigned to work on the case by using the @@USER_LOGGED system variable to get that user's unique ID. Then, pass that unique ID to the userInfo() function to look up his/her email address. For example:

$aUser = userInfo(@@USER_LOGGED);
$to = $aUser['mail'];
PMFSendMessage(@@APPLICATION, 'boss@example.com', $to, '', '', 'Some Message Title', 'someTemplate.html');

Emailing the Supervisor of a Case's Assigned User

To send a message to the supervisor of the current assigned user for a case, first use the InternaCases::loadCase() to look up who is currently assigned to work on the case and then use the Users::Load() method to get that user's supervisor. Finally, use userInfo() to get the supervisor's email.

For example, to email the supervisor of the user assigned to the current case when the case is overdue:

G::LoadClass("users");
$c = new Cases();
$aCase = $c->loadCase(@@APPLICATION, @%INDEX);
$u = new Users();
$aUser = $u->Load($aCase['CURRENT_USER_UID']);
if (!empty($aUser['USR_REPORTS_TO'])) {
    $aSupervisor = userInfo($aUser['USR_REPORTS_TO']);
    PMFSendMessage(@@APPLICATION, 'admin@example.com', $aSupervisor['mail'], $aUser['USR_EMAIL'],
        '', 'Case is Overdue', 'overdueTemplate.html');
}
else {
    @@ERROR = "There is no supervisor for user {$aCase['CURRENT_USER']}.";
   $g = new G();
   $g->SendMessageText(@@ERROR, "ERROR");
}

Emailing the Previous User of a Case

To send a message to a user who worked on a previous task in the case, create a trigger that fires during that previous task which saves the user's unique ID to a case variable.

For example, in a process to approve purchase requests, an email message needs to be sent to the purchase requester, informing him/her whether the purchase was approved or disapproved. In the first task when the requester fills out the purchase request form, fire the following trigger:

@@requesterId = @@USER_LOGGED;

In the subsequent task, when the manager decides to approve or disapprove the purchase request, fire the following trigger to send an email to the requester:

//check if the case variable has been set and is not empty
if (isset(@@requesterId) and !empty(@@requesterId)) {
   $aUserTo = userInfo(@@requesterId);
   $aUserFrom = userInfo(@@USER_LOGGED);
   PMFSendMessage(@@APPLICATION, $aUserFrom['mail'], $aUserTo['mail], '', '', 'Purchase Request Decision',
      '
purchaseDecision.html');
}

Emailing the Previous User with a Database Query

Another way to find the user who worked on a previous task in a case is to look up the record for that task in the wf_<WORKSPACE>.APP_DELEGATION table. There is a record for each task in a case with the last user to work on that task. First, look up the unique ID for the task with the taskList() web service at ADMIN > Settings > Web Services Test (or look it up in the wf_<WORKSPACE>.TASK.TAS_UID field in the database). Then, use executeQuery() in a trigger to look up the user who worked on a particular task for the case in the wf_<WORKSPACE>.APP_DELEGATION.USR_UID field.

For example, to send a message to a user who worked on a task with the ID "7710617204e67abaabfb1c9082177702" in the current case:

$taskId = "7710617204e67abaabfb1c9082177702";
$caseId = @@APPLICATION;
$query = "SELECT USR_UID FROM APP_DELEGATION WHERE APP_UID='$caseId' AND TAS_UID='$taskId'";
$tasks = executeQuery($query);
if (is_array($tasks) and count($tasks) > 0) {
   //get the last record, in case the task was repeated in the case
   $userId = $tasks[count($tasks)]['USR_UID'];
   $aUser = userInfo($userId);
   PMFSendMessage(@@APPLICATION, 'boss@example.com', $aUser['mail'], '', '', 'Some Message Title', 'someTemplate.html');
}

Emailing the Next Assigned User

An email can be sent out to the user assigned to work on the next task in two ways:

  1. Using the PMFGetNextAssignedUser() function for tasks with Cyclical Assignment.
  2. Looking up the next user in the APP_DELEGATION table after routing from the previous task.

The second way is more reliable and works with any type of assignment rule.

For Next Tasks with Cyclical Assignment

If the next task uses cyclical assignment, the next assigned user in a case can be looked up using the PMFGetNextAssignedUser() function. The parameters of this function require the unique IDs for the case and the task, which can be looked up with taskList() at ADMIN > Settings > Web Services Test or by querying the wf_<WORKFLOW>.TASK.TAS_UID field in the database.

For example, the following trigger sends an email message to the next user who will be assigned to work on the current case.

$taskId = 'XXXXXXXXXXXXXXXXXXXXXXXX'; //set to the unique ID for next task
$aUser = PMFGetNextAssignedUser(@@APPLICATION, $taskId);
if (is_array($aUser) and count($aUser) > 0) {
 PMFSendMessage(@@APPLICATION, "Mr. Boss <boss@example.com>", $aUser['USR_EMAIL'], '', '',
   'You are assigned to next task', 'template.html');
}
else {
   $g = new G();
   $g->SendMessageText("Unable to lookup next assigned user!", "ERROR");
}

Remember that the PMFGetNextAssignedUser() function only works if the next task uses cyclical assignment. If the next task uses any other type of assignment rule, it is necessary to use the following method.

For Next Tasks with Any Type of Assignment Rule

The assigned user in the next task can be looked up in the wf_<WORKSPACE>.APP_DELEGATION.USR_UID field in the database with a trigger that fires after routing from the previous task. At that point, the next task has already been created in the database, although the case is still in the previous task. This method works for tasks with any type of assignment rule.

For example, the following trigger sends an email message to the next user who will be assigned to work on the current case.

//ID of next task which can be found in the @@TASK variable in the next task in the debugger:
$nextTaskId = '67156450657e5b7bc47c393009386672';
$caseId = @@APPLICATION;
//lookup the user assigned to the next task in the case
$query = "SELECT USR_UID FROM APP_DELEGATION WHERE APP_UID='$caseId' AND
    DEL_INDEX=( SELECT MAX(DEL_INDEX) FROM APP_DELEGATION WHERE APP_UID='$caseId'
    AND TASK_UID='$nextTaskId' )"
;
$result = executeQuery($query) or
   die("Error in query: $query");
$aUser = userInfo($result[1]['USR_UID']);
$to = $aUser['firstname'] .' '. $aUser['lastname'] .' <'. $aUser['mail'] .'>';
PMFSendMessage(@@APPLICATION, "Mr. Boss <boss@example.com>", $to, '', '',
   'You are assigned to next task', 'template.html');

Emailing the Next Assigned Users of Parallel Tasks

The previous code example will have problems if the next tasks are parallel tasks, because their index numbers might not be the maximum index number. In that case, search for particular task IDs in the wf_<WORKSPACE>.APP_DELEGATION.TAS_UID field in the database. Task IDs can be found with taskList() at ADMIN > Settings > Web Services Test or by querying the wf_<WORKFLOW>.TASK.TAS_UID field in the database.

For example, the following trigger code set to fire after routing in the previous task will look up the next tasks in the process, which are three parallel tasks with the unique IDs "8494848774f28459638eb76005941643", "3466222164f2951faaf2915011308833" and "2935650394f297698b78467062625755":

$caseId = @@APPLICATION;
//lookup the user assigned to the next task in the case
$query = "SELECT USR_UID FROM APP_DELEGATION WHERE APP_UID='$caseId' AND DEL_THREAD_STATUS='OPEN' AND
   (TAS_UID='8494848774f28459638eb76005941643' OR '3466222164f2951faaf2915011308833'
   OR '2935650394f297698b78467062625755')"
;
$aUsers = executeQuery($query) or die("Error executing query: \n$query");
if (is_array($aUsers) and count($aUsers) > 0) {
   $to = '';
   foreach ($aUsers as $aUser) {
      $aInfo = userInfo($aUser['USR_UID']);
      $to .= ($to == '' ? '' : ', ') . $aInfo['mail'];
   }
   PMFSendMessage(@@APPLICATION, "Mr. Boss <boss@example.com>", $to, '', '',
      'You are assigned to the next tasks', 'template.html');
}

Emailing all Assigned Users of a Task

Sending out an email to all users in the assignment pool of a specified task can be useful, especially for self-service tasks, where a user is not automatically assigned to a task.

To send an email to all assigned users of a specified task, first look up the unique ID for the task by either using the taskList() web service test or by querying the database:

 SELECT CON_ID FROM CONTENT WHERE CON_CATEGORY='TAS_TITLE'

Using the unique ID of the task, look up all the users that are assigned to that task in the wf_<WORKSPACE>.TASK_USER table. If a group is assigned to the task, then also look up all the members of that group in the wf_<WORKSPACE>.GROUP_USER table.

In this example, an email is sent to all users that are assigned to the "Review Proposal" task, which has a unique ID of "2180652364e08ac6275dbb7037406882":

$taskId = "2180652364e08ac6275dbb7037406882"; //change to unique ID for the task
$assignedUsers = array(); //empty array to hold the UIDs of the assigned users to the task
$userQuery = "SELECT USR_UID FROM TASK_USER WHERE TAS_UID = '$taskId' AND TU_RELATION = 1";
$groupQuery = "SELECT GU.USR_UID FROM GROUP_USER GU, TASK_USER TU WHERE
   TU.TAS_UID = '$taskId' AND TU.TU_RELATION = 2 AND TU.USR_UID = GU.GRP_UID"
;
$users = executeQuery($userQuery);
if (is_array($users) and count($users) > 0) {
   foreach ($users as $user)
      $assignedUsers[] = $user['USR_UID'];
}
$users = executeQuery($groupQuery);
if (is_array($users) and count($users) > 0) {
   foreach ($users as $user)
      $assignedUsers[] = $user['USR_UID'];
}
 
$assignedUsers = array_unique($assignedUsers); //eliminate any duplicates in array
$emailTo = "";  
foreach ($assignedUsers as $assignedUser) {
   $aUser = userInfo($assignedUser);
   $emailTo .= (empty($emailTo) ? "" : "," ) . $aUser['mail'];
}
if (!empty($emailTo)) {
   PMFSendMessage(@@APPLICATION, 'boss@example.com', $emailTo, '', '',
      "New self-service case to be claimed", 'unassignedCase.html');
}

Emailing All Assigned Users of the Next Task(s)

Like the previous example, an email can be sent out to all the users in the assignment pool for the next task(s) in the process. Unlike the previous example, the unique ID of the task(s) does not need to be known, since it is automatically looked up in the ROUTE table based on the current task stored in the @@TASK system variable.

$taskId = @@TASK; //current task
//lookup next task(s), if the current task isn't a final task
$tasks = executeQuery("SELECT ROU_NEXT_TASK FROM ROUTE WHERE TAS_UID='$taskId' AND ROU_NEXT_TASK<>'-1'");
$taskList = ''; //build list of next task(s)
foreach ($tasks as $task) {
   $taskList .= (empty($taskList) ? '' : ', ') . "'" . $task['ROU_NEXT_TASK'] . "'";
}
 
$assignedUsers = array(); //empty array to hold the UIDs of the assigned users to the task
$userQuery = "SELECT USR_UID FROM TASK_USER WHERE TAS_UID IN ($taskList) AND TU_RELATION = 1";
$groupQuery = "SELECT GU.USR_UID FROM GROUP_USER GU, TASK_USER TU WHERE
   TU.TAS_UID IN ($taskList) AND TU.TU_RELATION = 2 AND TU.USR_UID = GU.GRP_UID"
;
 
$users = executeQuery($userQuery);
if (is_array($users) and count($users) > 0) {
   foreach ($users as $user)
      $assignedUsers[] = $user['USR_UID'];
}
 
$users = executeQuery($groupQuery);
if (is_array($users) and count($users) > 0) {
   foreach ($users as $user)
      $assignedUsers[] = $user['USR_UID'];
}
 
$assignedUsers = array_unique($assignedUsers); //eliminate any duplicates in array
$emailTo = "";  
foreach ($assignedUsers as $assignedUser) {
   $aUser = userInfo($assignedUser);
   $emailTo .= (empty($emailTo) ? "" : "," ) . $aUser['mail'];
}
if (!empty($emailTo)) {
   PMFSendMessage(@@APPLICATION, 'boss@example.com', $emailTo, '', '',
      "New self-service case to be claimed", 'unassignedCase.html');
}

Emailing all Participants in a Case

An email can be sent out to all the users who have participated in a specified case to keep them apprised of the progress of that case.

To send an email to all users who have participated in a case, first look up the unique ID for the case in one of the following ways:

  1. Use the @@APPLICATION system variable of the current case.
  2. Look up the case with the caseList() web service.
  3. Look up the case in the wf_<WORKSPACE>.APPLICATION.APP_UID or wf_<WORKSPACE>.APP_DELEGATION.APP_UID fields with an SQL query.

With the unique ID of the case, look up all the users who have been assigned to the case in the wf_<WORKSPACE>.APP_DELEGATION.USR_UID field and add them to the list of email recipients.

In this example, an email is sent to all users who have participated in the current case:

$caseId = @@APPLICATION; //UID for current case
$users = executeQuery("SELECT DISTINCT USR_UID FROM APP_DELEGATION WHERE APP_UID = '$caseId'");
if (is_array($users) and count($users) > 0) {
   $emailTo;    //empty string to hold the emails of the participants in case
   foreach ($users as $user) {
      $aUser = userInfo($user['USR_UID']);
      $emailTo .= (empty($emailTo) ? "" : "," ) . $aUser['mail'];
   }
   PMFSendMessage(@@APPLICATION, 'boss@example.com', $emailTo, '', '',
      "Update on Case Progress", 'caseStatus.html');
}

Emailing Members of a Department

Sending an email to all members of a department is very similar to sending an email to members of a group, but the USERS.DEP_UID field is queried.

In this example, the members of a department named "Sales" are looked up in the ProcessMaker database and an email is sent to all members:

$dptName = 'Sales';  //change to name of department
$query = "SELECT DISTINCT U.USR_UID FROM USERS AS U, CONTENT AS C WHERE " .
   "C.CON_CATEGORY='DEPO_TITLE' AND C.CON_VALUE='$dptName' AND C.CON_ID=U.DEP_UID";
$result = executeQuery($query);
if (!is_array($result) or count($result) < 1) {
   $g = new G();
   $g->SendMessageText("Unable to find any users in department '$dptName'.", "WARNING");
}
else {
   $to = '';
   foreach ($result as $record) {
      $aInfo = userInfo($record['USR_UID']);
      if (empty($to))
         $to = $aInfo['mail'];
      else
         $to .= ', ' . $aInfo['mail'];
   }
   PMFSendMessage(@@APPLICATION, 'boss@example.com', $to, '', '',
      "Work for $dptName", 'positiveExpense.html');
}

In this example, an email is sent to all users who have participated in the current case, and all master process or subprocess cases associated with the current case:

$caseId = @@APPLICATION; //UID for current case
$query = "SELECT DISTINCT USR_UID FROM APP_DELEGATION WHERE APP_UID =
   (SELECT APP_UID FROM SUB_APPLICATION WHERE APP_UID = '$caseId' OR APP_PARENT = '$caseId')"
;
$users = executeQuery($query);
if (is_array($users) and count($users) > 0) {
   $emailTo; //empty string to hold the emails of the participants in case
   foreach ($users as $user) {
      $aUser = userInfo($user['USR_UID']);
      $emailTo .= (empty($emailTo) ? "" : "," ) . $aUser['mail'];
   }
   PMFSendMessage(@@APPLICATION, 'boss@example.com', $emailTo, '', '',
      "Update on Case Progress", 'caseStatus.html');
}

Emailing Members of a Group

In this example, the members of a group are looked up in the ProcessMaker database and an email is sent to each member of a group named "employees".

$groupName = 'employees';  //change to name of group
$query = "SELECT DISTINCT GU.USR_UID FROM CONTENT AS C, GROUP_USER AS GU WHERE " .
   "C.CON_CATEGORY='GRP_TITLE' AND C.CON_VALUE='$groupName' AND C.CON_ID=GU.GRP_UID";
$result = executeQuery($query);
if (!is_array($result) or count($result) < 1) {
   $g = new G();
   $g->SendMessageText("Unable to find any users in group '$groupName'.", "WARNING");
}
else {
   $to = '';
   foreach ($result as $record) {
      $aInfo = userInfo($record['USR_UID']);
      if (empty($to))
         $to = $aInfo['mail'];
      else
         $to .= ', ' . $aInfo['mail'];
   }
   PMFSendMessage(@@APPLICATION, 'boss@example.com', $to, '', '',
      "Work for $dptName", 'positiveExpense.html');
}

Emailing Users with a Role

Sending an email to all users with a specific role requires first looking up the unique ID of the role in the rb_<WORKSPACE>.ROLES table and then querying the wf_<WORKSPACE>.USERS.USR_ROLE field for that unique ID.

In this example, the users with the "PROCESSMAKER_MANAGER" role are looked up in the ProcessMaker database and an email is sent to all those users:

$roleCode = 'PROCESSMAKER_MANAGER';  //change to code for role
$roleQuery = executeQuery("SELECT ROL_UID FROM ROLES WHERE ROL_CODE='$roleCode'", 'rbac');
$roleUid = $roleQuery[1]['ROL_UID'];
$result = executeQuery("SELECT USR_UID FROM USERS WHERE USR_ROLE='$roleUid'");
if (!is_array($result) or count($result) < 1) {
   $g = new G();
   $g->SendMessageText("Unable to find any users with role '$roleCode'.", "WARNING");
}
else {
   $to = '';
   foreach ($result as $record) {
      $aInfo = userInfo($record['USR_UID']);
      if (empty($to))
         $to = $aInfo['mail'];
      else
         $to .= ', ' . $aInfo['mail'];
   }
   PMFSendMessage(@@APPLICATION, 'boss@example.com', $to, '', '',
      "Meeting for all managers next Friday", 'managersMeeting.html');
}

Emailing when Cases are Canceled/Paused/Reassigned

ProcessMaker does not provide a way to fire a trigger when these actions occur in a case. The only way to get around this problem is to add code directly to the functions Cases::deleteCase, Cases::cancelCase(), Cases::pauseCase, Cases::unpauseCase() or Cases::reassignCase(), which are defined in the file workflow/engine/classes/class.case.php.

For example, to send an email notification to the next user when a case is reassigned to him/her, the following code could be added to the end of the Cases::reassignCase() function:

G::LoadClass("pmFunctions");
$aUser = userInfo($newUserUID);
PMFSendMessage($sApplicationUID, "admin@example.com", $aUser['mail'], '', '',
   "Assigned to the case!", "someTemplate.html");

Debugging Email Notifications

Email notifications can fail for a number of reasons. If emails aren't being received, check the following issues to figure out what is causing the problem.

First, check the email server connection configuration and make sure that the email server is functioning by pinging it. Also make sure that the ProcessMaker server is configured to periodically execute cron.php, to send the emails.

Check the PMFSendMessage() Return Value

If the email was sent out by PMFSendMessage() in a trigger, then check the return value. If 0, then there is probably a problem in the parameters of the function. Perhaps one of the email addresses is not recognized as an email address. Perhaps the name of the template file was misspelled. Remember that template names are case sensitive.

Assign the return value of the PMFSendMessage() function to a case variable and run a case with the debugger turned on to see the return value.

@@ret = PMFSendMessage(...);

Check the APP_MESSAGE Table

Check whether a record has been written to the wf_<WORKSPACE>.APP_MESSAGE table in the database. (To avoid logging in MySQL from the command line, phpMyAdmin can be used to view the database from a web browser.)

Every email message to be sent out will be stored in the wf_<WORKSPACE>.APP_MESSAGE table in the database. When the record is first written to the database, the APP_MSG_SENT field will be set to the current datetime. (Note that the APP_MSG_SENT field doesn't indicate the time when the message was sent to the email server.) When the email message is sent to the email server by the cron.php script, the APP_MSG_STATUS field will change from "pending" to "sent".

Check the Output of cron.php

When the cron.php script is executed, it sends every message in the wf_<WORKSPACE>.APP_MESSAGE table whose status is "pending" to the email server. cron.php keeps a log of its activities. If emails were sent out, a record should be written in the shared/log/cron.log file. If an error occurred while trying to send out emails, a record should be written to the shared/log/cronError.log file.

If the log files don't indicate anything, execute cron.php manually from the command line and check the output.

Log Module to Manage Notifications

The log module displays information of all mails sent inside a process. This feature is optimized by emulating APP_MESSAGE inside the log, allowing emails to be searched using different search parameters.

Take into consideration that only users with the PM_SETUP and PM_SETUP_LOGS permissions assigned to their role will have access to the email log.

The following notifications will be stored inside it:

When emails are sent, their registry is stored at ADMIN > Settings > Logs > Emails

Email Log Options

Once an email has been sent, it will be stored in wf_<workspace>.APP_MESSAGE table and displayed in the log list with the following information:

  • #: Displays the number of the case where the email was sent.
  • Case: Displays the name of the case where the email was sent.
  • Process: Name of the process where the email was sent.
  • Task: Name of the task where the email was configured to be sent.
  • Type: Displays the type of notification. There are two types of notifications: "Trigger" if an email was sent using a trigger (using the PMFSendMessage() function, for example), and "Derivation" if the email was sent using a Task Notification or a Case Note.
  • Date: Date when the email was sent.
  • Subject: The subject (title) of the email.
  • From: The email address of the person who sent the email.
  • To: The email address to whom the email was sent.
  • Error Email: Displays any error that might have occurred if the email wasn't sent correctly.
  • Status: Displays the status of the message. If the email was sent its status will be Sent, otherwise it will be Pending. This status can be changed in if a lot of mails were on queue and they weren't sent correctly. If this value is changed, it will also be changed in the APP_MESSAGE table.

Below each email description, a preview of the message body is displayed. Click on the icon to expand the information, and the icon to contract it.

In the example above, an email was sent by adding a case note.

If the template was created with a customized style, font size, color, etc. the format will be displayed in the preview. In the example below, an event was executed and its template was created using a customized style:

Searching Emails

One of the advantages of the email log is the ability to search for an email using selected criteria. The search criteria are:

  • Filter by: Applies a filter.
    • All: Displays all the emails sent.
    • Cases: Displays only emails that have been sent inside cases. This includes: Triggers, Task Notifications, Events.
    • Test: Displays only records of emails that were sent by testing an Email Server configuration. If this option is selected, the Process dropdown filter will be disabled.
    • External Registration: Displays only records of emails that were sent by this plugin. This option is only available when the External Registration plugin is enabled. If this option is selected, the Process dropdown filter will be disabled
  • Process: Search by process name or by all processes created in the current workspace.
  • Status: Search by status: All, Participated or Pending.
  • Delegate Date From: To: Search by the date when email was sent.