How I foresee this working, is that the HMI be configured with an SMTP server as in this tutorial: Link. When a user account is created, they will need to add their email to an unused “Group” using the “Contact editor” object:
Note: The “Contact editor” object supports up to 16 groups, but precautions must be taken to ensure users only have access to this object during initial account creation or while overseen by an admin user.
A separate field should be made such that the user can associate the “Group” with their account. I would recommend storing both the username and “group” within a recipe database: Link

When the user needs to change their password, the only stipulation is that they will need to enter their username and group id [optional] to validate their account:
After validation a macro may be used to generate a random verification code, here is an example of a macro that will generate a random 5-digit integer:
macro_command main()
int verify = 0
RAND(verify)
while verify < 10000
RAND(verify)
DELAY(10)
wend
SetData(verify, "Local HMI", LW, 0, 1)
end macro_command
That code may be read by an “Alarm” using the “Multi-watch” function. This means that 16-alarms will need to be created, 1 for each potential “group” as the alarms send emails via group ID. The alarm triggered (e.g., email sent) should be dependent on the selected group which can be accomplished via Macro:
macro_command main()
char symbal[1]="%"
char Apostrophe[1]="'"
int verify = 0
short group = 0
char name[15]
GetData(name[0], "Local HMI", LW, 0, 15)
char sql[100] = "SELECT * FROM Accounts WHERE Name LIKE " // form a SQL query
// to search the recipe called "Accounts" for the user's "Name" where "Name"
// is an item or column in the recipe
// This forms the query via concatenation
StringCat(Apostrophe[0], sql[0])
StringCat(symbal[0], sql[0])
StringCat(name[0], sql[0])
StringCat(symbal[0], sql[0])
StringCat(Apostrophe[0], sql[0])
RecipeQuery(sql[0], n_records) // This sends the query
if n_records > 0 then // if an account actually exists n_records = 1
RecipeQueryGetRecordID(recordID, 0) // get the record id of that account
RecipeGetData(group, "Accounts.group", recordID) // get the group id of the account
RAND(verify) // generate verification code
while verify < 10000
RAND(verify)
DELAY(10)
wend
SetData(verify, "Local HMI", LW, 0, 1) // set verification code
DELAY(50)
SetData(group, "Local HMI", LW, 99, 1) // trigger alarm according to group id
end if
end macro_command
Note: An alarm that checks for a user “group” ID of ‘1’ or “B” may be configured as shown.