How to Automate Password Expiry Reminders?

Question
I want to automate the process of sending email reminders to Customer Community users when their password is about to expire in 7 days. However, my organization uses multiple profiles for Customer Community users, and each profile has its own password expiration policy (e.g., 90-day expiration, 180-day expiration, etc.). Since new profiles are created periodically, I want to avoid managing these password policies in Custom Metadata Types (CMDT), as it would lead to duplicative metadata management. Instead, I’m looking for a way to:
- Use a scheduled-triggered Flow that runs on users with
UserType = CspLitePortal
. - Query the ProfilePasswordPolicy metadata type to determine the expiration period (via invocable Apex for bulk processing).
- Compare the expiration period with each user’s last password reset date.
- Send an email notification if the password will expire in 7 days.
Answer
One possible solution involves using a Flow with an invocable Apex action that queries metadata using the Apex Metadata API. Here’s how you can approach this:
Flow Setup:
You can create a scheduled Flow that runs at regular intervals to check Customer Community users’ passwords. The Flow should focus on users who have the UserType
of CspLitePortal
. The key challenge here is to avoid manually managing different profiles and their expiration policies in CMDT, so the plan is to query this data dynamically using Apex.
Invocable Apex:
The Flow will call an invocable Apex method, passing in the profile IDs of all active Customer Community users. The invocable Apex method will use the Apex Metadata API to fetch the expiration period from the ProfilePasswordPolicy metadata. The solution requires installing the GitHub package apex-mdapi
(last updated at version 42). This package provides access to the ProfilePasswordPolicy metadata type, which is available for query starting from version 40.
Apex Code Example:
Below is an example of how the invocable Apex code could be structured
// Step 1: Get all Customer Community profiles
Set<String> customerCommunityProfileFullNames = new Set<String>();
for (Profile customerCommunityProfile : [SELECT Id, Name, UserType
FROM Profile
WHERE UserType = 'CspLitePortal']) {
// Convert Profile.Name to an API-friendly format
customerCommunityProfileFullNames.add(customerCommunityProfile.Name.replace(' ', '_'));
}
// Step 2: Set up the Metadata API service
MetadataService.MetadataPort service = new MetadataService.MetadataPort();
service.SessionHeader = new MetadataService.SessionHeader_element();
service.SessionHeader.sessionId = UserInfo.getSessionId();
// Step 3: Query for ProfilePasswordPolicy full names
List<MetadataService.ListMetadataQuery> queries = new List<MetadataService.ListMetadataQuery>();
MetadataService.ListMetadataQuery queryProfilePasswordPolicy = new MetadataService.ListMetadataQuery();
queryProfilePasswordPolicy.type_x = 'ProfilePasswordPolicy';
queries.add(queryProfilePasswordPolicy);
// Fetch the metadata for ProfilePasswordPolicy
MetadataService.FileProperties[] fileProperties = service.listMetadata(queries, 62);
Set<String> profilePasswordPolicyFullNames = new Set<String>();
for (MetadataService.FileProperties fileProperty : fileProperties) {
String profilePortionOfFullName = fileProperty.fullName
.substringBefore('_profilePasswordPolicy'); // Extract profile name
if (customerCommunityProfileFullNames.contains(profilePortionOfFullName)) {
profilePasswordPolicyFullNames.add(fileProperty.fullName);
}
}
// Step 4: Retrieve ProfilePasswordPolicy metadata
MetadataService.ProfilePasswordPolicy[] profilePasswordPolicies =
(MetadataService.ProfilePasswordPolicy[])
service.readMetadata('ProfilePasswordPolicy', profilePasswordPolicyFullNames).getRecords();
// Log expiration periods for debugging
for (MetadataService.ProfilePasswordPolicy profilePasswordPolicy : profilePasswordPolicies) {
system.debug(profilePasswordPolicy.fullname + ' with expiration: ' + profilePasswordPolicy.passwordExpiration);
}
This Apex code retrieves password expiration policies for Customer Community users by querying metadata using the Metadata API. It follows a structured approach to fetch relevant password policies associated with different profiles.
First, it collects all profiles assigned to Customer Community users (UserType = 'CspLitePortal'
) and formats their names to match API naming conventions (replacing spaces with underscores). Then, it initializes the Metadata API service and sets up the session header using the current user’s session ID.
Next, the code queries Salesforce Metadata to find ProfilePasswordPolicy
records, which define password expiration settings for profiles. It extracts the profile names from the metadata and filters out only those relevant to Customer Community users.
Finally, it retrieves the ProfilePasswordPolicy
metadata for the selected profiles, extracting password expiration settings. The expiration periods are then logged for debugging. This approach allows for dynamically fetching expiration policies without hardcoding values, ensuring that newly created Customer Community profiles are automatically included in the process. However, due to Metadata API limitations, batch processing may be required if more than ten profiles need to be retrieved at once.
Complications to Consider:
Callout Limits: The readMetadata
operation is limited to 10 records at a time. If you need to fetch more, you’ll have to loop and make multiple callouts to avoid hitting the limit.
Missing ProfileMetadata: Not every profile will have a ProfilePasswordPolicy
. Some profiles may have their expiration settings stored in the SecuritySettings file under the Settings metadata type. If you encounter profiles with no metadata, you will need to retrieve their expiration policy from a different source.
No Session ID in Scheduled Flows: In a scheduled Flow, UserInfo.getSessionId()
will not work because there is no active session in the context. To resolve this, you will need to use Named Credentials with an OAuth Auth Provider for authentication. This allows the use of a client credentials flow for the Metadata API calls.
Next Steps:
You can extend the invocable Apex code to send email reminders if the expiration period is within 7 days.
You can also handle the flow’s waiting period by adding a WAIT
element before calling the invocable Apex, allowing it to run efficiently without exceeding limits.
In summary, this solution leverages the Apex Metadata API for dynamic querying of password expiration settings per profile, avoids CMDT for managing password policies, and uses scheduled flows to trigger the email reminders based on user-specific expiration policies.
Kick Start Your Journey with Real-Time Project-Based Salesforce Learning
Our Salesforce course is designed to provide you with a comprehensive understanding of the Salesforce platform, empowering you with the essential skills to thrive in the CRM industry. The course covers key topics such as Salesforce Admin, Developer, and AI, seamlessly integrating theory with practical application. By engaging in hands-on projects and assignments, you’ll develop the expertise to solve real-world business challenges using Salesforce solutions. Our expert trainers ensure you gain the technical knowledge and industry insights needed to excel in the Salesforce ecosystem.
In addition to technical skills, our Salesforce Training in Minneapolis offers personalized mentorship, certification guidance, and interview coaching to support your career growth. You’ll have access to a wide range of study materials, live projects, and dedicated support throughout the course. By the time you complete the program, you will be well-prepared for certification exams and equipped with the problem-solving skills that employers value. Start your Salesforce career today and unlock a world of opportunities. Sign up for a free demo now!