Use PDIs? Take our 5-minute survey to help shape the PDI roadmap.

Need Help Sending a Consolidated Email After Removing Users in Flow Designer

n-ssurabhi
Tera Contributor

Hi Team,

I'm working on a ServiceNow Flow Designer requirement and would appreciate some guidance on the final part of the solution.

Requirement

  1. Run a scheduled flow every month.
  2. Check which members of the "Finance Group" have not been selected as an approver in the last 6 months.
  3. Remove those users from the "Finance Group".
  4. Send a notification email listing all users who were removed from the group.

Current Progress

I have successfully implemented most of the logic:

  • The flow identifies users who have not been used as approvers in the last 6 months.
  • The users are being removed from the group as expected.

Challenge

The issue I'm facing is with the email notification.

I have a For Each loop that iterates through all eligible users (currently around 22 records). During each iteration, the user is removed from the group and I get the corresponding user details.

What I'd like to achieve is:

  • Store the details of every removed user during the loop execution.
  • After the loop completes, send a single consolidated email containing:
    • Total number of users removed.
    • List of all removed users.

What I Have Tried

I attempted to use:

  • Set Flow Variable
  • Append to Flow Variable

However, I'm unable to successfully accumulate the user details across all iterations and use them in the final email notification.

  1. What is the recommended way to collect values from each iteration of a For Each loop in Flow Designer?
  2. Should I use a String flow variable, an Array flow variable, or another approach?
  3. How can I build a consolidated list of removed users and reference it in a single email after the loop completes?

Any examples or best practices would be greatly appreciated.

Thank you!

3 REPLIES 3

rajeshoffic
Tera Contributor

Hi,

You can achieve this by using a string flow variable and the "Append to Flow Variables" action inside the ForEach loop.

Solution

  1. Create two Flow Variables before the For Each loop:
  • Removed Users – String
  • Removed User Count – Integer
  1. Initialize the variables:
  • Removed Users = empty
  • Removed User Count = 0
  1. Inside the For Each loop, after successfully deleting the Group Member record:
  • Increment Removed User Count by 1.
  • Use "Append to Flow Variables" to add the user details to the Removed Users variable.

For example:

Removed Users:
User Name - Email Address

For the next iteration, append the next user to the same variable instead of overwriting the existing value.

  1. Place the Send Email action outside the For Each loop.

This is important because it ensures that only one email is sent after all eligible users have been removed.

The email can contain:

Total Users Removed: [Removed User Count]

Users Removed:
[Removed Users]

Alternative Approach

You can also use a custom event with gs.eventQueue() after the For Each loop is completed.

For example:

gs.eventQueue('custom.finance.users.removed', current, removedUserList, '');

The collected user details can be passed through Event Parm 1 and used in the notification.

If the removed users themselves need to receive the notification, make sure to collect their details before deleting the Group Member record.

Recommendation

For this requirement, I would recommend using a string flow variable with "Append to Flow Variables." It is simple and works well when the requirement is to collect all removed users and send one consolidated email after the loop.

Hope this helps. If this solution is helpful, please click "Helpful."

rajeshoffic
Tera Contributor

Hi,

You can achieve this by using a string flow variable and the "Append to Flow Variables" action inside the ForEach loop.

Solution

  1. Create two flow variables before the for each loop:
  • Removed Users – String
  • Removed User Count – Integer
  1. Initialize the variables:
  • Removed Users = empty
  • Removed User Count = 0
  1. Inside the For Each loop, after successfully deleting the Group Member record:
  • Increment Removed User Count by 1.
  • Use "Append to Flow Variables" to add the user details to the Removed Users variable.

For example:

Removed Users:
User Name - Email Address

For the next iteration, append the next user to the same variable instead of overwriting the existing value.

  1. Place the Send Email action outside the For Each loop.

This is important because it ensures that only one email is sent after all eligible users have been removed.

The email can contain:

Total Users Removed: [Removed User Count]

Users Removed:
[Removed Users]

Alternative Approach

You can also use a custom event with gs.eventQueue() after the for each loop is completed.

For example:

gs.eventQueue('custom.finance.users.removed', current, removedUserList, '');

The collected user details can be passed through Event Parm 1 and used in the notification.

If the removed users themselves need to receive the notification, make sure to collect their details before deleting the Group Member record.

Recommendation

For this requirement, I would recommend using a string flow variable with "Append to Flow Variables." It is simple and works well when the requirement is to collect all removed users and send one consolidated email after the loop.

Hope this helps. If this solution is helpful, please click "Helpful."

Vishal Jaswal
Tera Sage

Hello @n-ssurabhi 

With flow designer you will be able to achieve the deletion however will not be able to generate one consolidated e-mail because of "for each" loop.

Hence, my recommendation is to create a Flow Action with Script Step as shown below:

(function execute(inputs, outputs) {

    
    var groupName = 'Finance Group';
    var monthsLookBack = 6;


    var removedGroupMembers = [];
    var removed_group_members_count = 0;

    try {
        // Get Finance Group 
        var grpGR = new GlideRecord('sys_user_group');
        if (!grpGR.get('name', groupName)) {            
            outputs.removed_group_members_list = 'ERROR: Finance Group not found';
            outputs.removed_group_members_count = 0;
            outputs.removed_group_members_html = '';
            return;
        }

        // Calculate cutoff date (6 months ago)
        var cutoffDate = new GlideDateTime(); //Current date/time
        cutoffDate.addMonthsUTC(-monthsLookBack); //Subtract 6 months

        // Get all Finance Group members
        var memberGR = new GlideRecord('sys_user_grmember');
        memberGR.addQuery('group', grpGR.getUniqueValue());
        memberGR.query();

        gs.info('Finance Group Total members to check: ' + memberGR.getRowCount());

        // Loop through each member
        while (memberGR.next()) {
            var userSysId = memberGR.getValue('user');
            var userName = memberGR.user.getDisplayValue();
            var userEmail = memberGR.user.email.toString();            

            // Count approvals in last 6 months (using GlideAggregate for speed)
            var approvalCount = 0;
            var approvalGR = new GlideAggregate('sysapproval_approver');
            approvalGR.addQuery('approver', userSysId);
            approvalGR.addQuery('sys_created_on', '>=', cutoffDate);
            approvalGR.addAggregate('COUNT');
            approvalGR.query();

            if (approvalGR.next()) {
                approvalCount = parseInt(approvalGR.getAggregate('COUNT'), 10) || 0; //Get the count, convert it to a number and default to 0 if anything goes wrong.
            }

            //  If No approvals then remove from group
            if (approvalCount === 0) {
                gs.info('Finance Group Member Removing: ' + userName);

                removedGroupMembers.push({
                    name: userName,
                    email: userEmail                   
                });
                removed_group_members_count++;

                // Delete the group membership
                var deleteGR = new GlideRecord('sys_user_grmember');
                if (deleteGR.get(memberGR.getUniqueValue())) {
                    deleteGR.deleteRecord();
                }
            }
        }

        // Build outputs for the email

        // Plain text list
        var plainList = '';
        for (var i = 0; i < removedGroupMembers.length; i++) {
            plainList += removedGroupMembers[i].name + ' (' + removedGroupMembers[i].email + ')\n';
        }

        // HTML table
        var htmlTable = '';
        if (removedGroupMembers.length > 0) {
            htmlTable = '<table border="1" cellpadding="8" cellspacing="0" ' +  'style="border-collapse:collapse;">';
            htmlTable += '<thead style="background:#f0f0f0;"><tr>' + '<th>#</th><th>Name</th><th>Email</th>' + '</tr></thead><tbody>';

            for (var j = 0; j < removedGroupMembers.length; j++) {
                htmlTable += 
                    '<tr>' +
                    '<td>' + (j + 1) + '</td>' +
                    '<td>' + removedGroupMembers[j].name + '</td>' +                  
                    '<td>' + removedGroupMembers[j].email + '</td>' +
                    '</tr>';
            }

            htmlTable += '</tbody></table>';
        }

        // Set the action outputs
        outputs.removed_group_members_list = plainList;
        outputs.removed_group_members_count = removed_group_members_count;
        outputs.removed_group_members_html = htmlTable;

        gs.info('Finance Group Clean up Completed. Users removed: ' + removed_group_members_count);

    } catch (ex) {
        gs.error('Finance Group Clean up ERROR: ' + ex.message);
        outputs.removed_group_members_list = 'ERROR: ' + ex.message;
        outputs.removed_group_members_count = 0;
        outputs.removed_group_members_html = '';
    }

})(inputs, outputs);


Flow Action Inputs - None
Flow Action Script Outputs:

VishalJaswal_0-1787340827634.png


Flow Action Outputs:

VishalJaswal_1-1787340843653.png


Flow:

VishalJaswal_2-1787340860907.png

 

VishalJaswal_5-1787340887809.png

 

 

VishalJaswal_9-1787341188521.png


Validation Results:

VishalJaswal_8-1787341167021.png

 

 

VishalJaswal_7-1787341145333.png

 


Hope that helps!