Email Generation Transform/Rule

We are working on setting up a logic to generate unique email addresses for every user who joins. The email format should follow this pattern:

  • Use either Preferred Firstname or Firstname — whichever is not null.

  • Follow that with a dot (.).

  • Then use either Preferred Lastname or Lastname — whichever is not null.

  • Finally, append @domain.com.

Example:

If the user’s name is John Doe, the email would be:
[email protected]

If there are multiple users with the same name, the emails should include a number suffix to keep them unique:
[email protected]
[email protected]
…and so on.

The number at the end is a counter to ensure uniqueness.


Our question:
What’s the best way to implement this logic to generate the email addresses as an identity attribute (work email) within SailPoint? We need to calculate these values in this order and ensure uniqueness directly in SailPoint.

Any suggestions or examples would be greatly appreciated!

Thanks in advance!

we can do this using transforms but achieving uniqueness is required. If you want to go with only [email protected] you can easily implement transform. But I suggest go through this links before proceeding:

Do you have any sample rule for this use case ? We cant use Transform here as uniqueness needs to be address while creating email for user? if you have anything specific to use case please share with us.

Hello @Gagan Juneja,

There are 2 ways to do it.

Approach 1 .

Use Identity Attribute Generator Rule

Approach 2.

Use Account Attribute Generator Rule.

You can use Identity Attribute generator rule to calculate the uniqueness and following algorithm would be work.

  1. Start
  2. Fetch the details of FirstName, LastName and Domain from Identity Attribute (Note that Domain is STATIC value, hence, using it in an identity attribute through STATIC transform will make your solution mor scalable with no requirement of changes in the rule when you move from 1 env to another.)
  3. Create a Search Attribute (No Indexed Attribute) in SailPoint which will store all values of mail attribute from AD (or whichever your email generation source is in it)
  4. Use Switch Cases and While Loop to generate the email IDs with uniqueness
  5. Break the loop once the unique value is found
  6. Stop.

Using Non Indexed Search attribute is a good option for uniqueness. Refer the below code. Note that we have used the Account Attribute Generator Rule approach and not identity attribute one but you can use the same logic as below for your approach as well.

  
import java.util.Iterator;
import sailpoint.object.*;
import java.util.ArrayList;
import sailpoint.api.*;
import java.util.List;
import org.apache.commons.lang.StringUtils;

// Normalizing the strings
public String normalizeInput(String inputString)
{
    if (inputString!=null && !inputString.isEmpty())
    {
        // Remove any non-alphanumerics
        inputString=inputString.replaceAll("[^A-Za-z0-9]", "");
        // Strip off any non-printables
        inputString=StringUtils.trimToNull(inputString);
    }
    return inputString;
}

//Check uniqueness of Generated upnPrefix
public boolean isUniqueUPNPrefix(String checkUPNPrefix)
{
  int numberFound = 0;
  List SOURCE_IDS = new ArrayList(Arrays.asList(new String[]{"442ed0376f40"}));
  String PROMOTED_ATTR_NAME = "UPNPrefix";
  String SEARCH_OP = "Equals"; 
  List SEARCH_VALUES = new ArrayList(Arrays.asList(new String[]{checkUPNPrefix}));
  numberFound = idn.attrSearchCountAccounts(SOURCE_IDS, PROMOTED_ATTR_NAME, SEARCH_OP, SEARCH_VALUES);
  
  if(numberFound == 0)
  {
  return true;
  }
  
  else 
  {
   return false;
  }
}



public String generateUpnPrefix(String firstName, String middleName, String lastName, String domainForEmailCreation)
{
    String alias = null;
	String upnPrefix = null;
	int iterator = 0;
	int counter = 1;
    int width = 3; // Total width of the counter, including leading zeros

    if((firstName == null) || (lastName == null))
    {
        return null;
    }

    else if((middleName != null) && (middleName != ""))
    {
		middleName = middleName.substring(0,1);
		do
		{
			switch (iterator)
			{
				case 0:
					alias = firstName + "." + lastName;
					break;
				case 1:
					alias = firstName + "." + middleName + "." + lastName;
					break;
				default:
					String counterStr = "" + counter;
						while (counterStr.length() < width) {
						    counterStr = "0" + counterStr;
						}
					alias = firstName + "." + lastName + counterStr;
					counter++;
					break;					
			}
			iterator++;
			upnPrefix = alias;
		
		} while(!(isUniqueUPNPrefix(upnPrefix)) && (iterator < 999));
		// Don't let the it loop forever if something goes wrong
		
		if((iterator >= 999) || (upnPrefix.isEmpty()) || upnPrefix == null)
        {
            return null;
        } 
		else
        {
            return upnPrefix;
        }
			
	}
	else {
		do
		{
			switch (iterator)
			{
				case 0:
					alias = firstName + "." + lastName;
					break;
				default:
					String counterStr = "" + counter;
						while (counterStr.length() < width) {
						    counterStr = "0" + counterStr;
						}
					alias = firstName + "." + lastName + counterStr;
					counter++;
					break;
			}
			
			iterator++;
			upnPrefix = alias;

		} while (!(isUniqueUPNPrefix(upnPrefix)) && (iterator < 999));
		// Don't let the loop forever if something goes wrong

		if(( iterator >= 999) || (upnPrefix.isEmpty()) || upnPrefix == null)
        {
            return null;
        } 
		else
        {
            return upnPrefix;
        }
	}
}

// Grabbing the Identity's Data and Main Code


	String firstName = normalizeInput(identity.getAttribute("firstname"));
	String middleName = normalizeInput(identity.getAttribute("legalMiddleName"));
	String lastName = normalizeInput(identity.getAttribute("lastname"));
	String domain = StringUtils.trimToEmpty(identity.getAttribute("domain"));
	
	return generateUpnPrefix(firstName, middleName, lastName, domain);
  

Document to Create and Use Non-Indexed Search attribute is as below.

Hello Gagan,

  1. Create an Non-Indexed Search Attribute as per below using POSTMAN or VS Code
{
"name": "MailAddress",
"displayName": "Mail",
"applicationAttributes": {
"328e7cec0f3c46d5a63efa29e5868762": "mail"
}
}
  1. Perform Non-Optimized Aggregation for Entra ID
  2. Once aggregation is completed, create and deploy the below identity attribute cloud rule

import java.util.Iterator;
import sailpoint.object.*;
import java.util.ArrayList;
import sailpoint.api.*;
import java.util.List;
import org.apache.commons.lang.StringUtils;

// Normalizing the strings
public String normalizeInput(String inputString)
{
    if (inputString!=null && !inputString.isEmpty())
    {
        // Remove any non-alphanumerics
        inputString=inputString.replaceAll("[^A-Za-z0-9]", "");
        // Strip off any non-printables
        inputString=StringUtils.trimToNull(inputString);
    }
    return inputString;
}

//Check uniqueness of Generated finalEmail
public boolean isUniqueMail(String checkUPNPrefix)
{
  int numberFound = 0;
  List SOURCE_IDS = new ArrayList(Arrays.asList(new String[]{"328e7cec0f3c46d5a63efa29e5868762"}));
  String PROMOTED_ATTR_NAME = "MailAddress";
  String SEARCH_OP = "Equals"; 
  List SEARCH_VALUES = new ArrayList(Arrays.asList(new String[]{checkUPNPrefix}));
  numberFound = idn.attrSearchCountAccounts(SOURCE_IDS, PROMOTED_ATTR_NAME, SEARCH_OP, SEARCH_VALUES);
  
  if(numberFound == 0)
  {
  return true;
  }
  
  else 
  {
   return false;
  }
}



public String generateEmail(String mailnickName, String domainForEmailCreation)
{
    String tempGeneratedEmail = null;
	String finalEmail = null;
	int iterator = 0;
	int counter = 1;
    int width = 3; // Total width of the counter, including leading zeros

    if((mailnickName == null))
    {
        return null;
    } else {
		do
		{
			switch (iterator)
			{
				case 0:
					tempGeneratedEmail = mailnickName + "@" + domainForEmailCreation;
					break;
				default:
					tempGeneratedEmail = mailnickName + counter + "@" + domainForEmailCreation;
					counter++;
					break;
			}
			
			iterator++;
			finalEmail = tempGeneratedEmail;

		} while (!(isUniqueMail(finalEmail)) && (iterator < 999));
		// Don't let the loop forever if something goes wrong

		if(( iterator >= 999) || (finalEmail.isEmpty()) || finalEmail == null)
        {
            return null;
        } 
		else
        {
            return finalEmail;
        }
	}
}

// Grabbing the Identity's Data and Main Code
	
	String mailnickName = normalizeInput(identity.getAttribute("mailnickName"));
	String domain = StringUtils.trimToEmpty(identity.getAttribute("domain"));
	
	return generateEmail(mailnickName, domain);
  1. Map it in identity profile
  2. Test.

I would recommend you to create an Account Attribute Cloud Rule and not identity attribute cloud rule because mailNickName is getting generated at identity attribute level and sequence of processing in identity profile is not controlled by us.

Regards,

Rohit Wekhande.