function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Alex.AcostaAlex.Acosta 

Regular Expressions / Show Template with Merge Field populated

My whole goal originally was to get an Email Template and passing in my records to see the merged field results to display it for a user since the template/script will changed based on different critera within the visualforce page wizard I was making, and in order to avoid changing code as much as possible I was hoping the use of a template would suffice.

 

Sadly I was unable to successfully find a solution to this. So I've gone the route of using Regular Expression to do my find/replace of the merge fields. I currently have this example which works online in other regular expression validators but not within Apex.

 

String emailTemplate = 'Dear {!Lead.FirstName},'+
'Thank you for responding to your exclusive invitation. Blah blah blah your invitation code is {!Lead.externalId__c}.'+
'Stay well,\n{!User.FirstName} {!User.LastName}\nCompany Name';
		
Pattern myPattern = Pattern.compile('(\\{!+([a-zA-Z_.]*\\.[a-zA-Z_]*)})');
Matcher myMatch = myPattern.matcher(emailTemplate);
System.debug('\n\nMatch found? ' + myMatch.matches() + '\n\n');

if(myMatch.matches()){
	while (myMatch.find()) {
		System.debug('\n\nStart index: ' + myMatch.start() + '\nEnd index: ' + myMatch.end() + '\n' + myMatch.group() + '\n\n');
	}
}

 

Once this issue is resolved, with the matching working correctly, any ideas on how to replace those values dynamicly?

 

Any help is greatly appreciated!

Alex.AcostaAlex.Acosta

I have resolved the issue with looping through groups. Now to dyanamicly insert the proper record with field value.

 

String emailTemplate = 'Dear {!Lead.FirstName},'+
'Thank you for responding to your exclusive invitation. Blah blah blah your invitation code is {!Lead.externalId__c}.'+
'Stay well,\n{!User.FirstName} {!User.LastName}\nCompany Name';
		
Pattern myPattern = Pattern.compile('(\\{!+([a-zA-Z_.]*\\.[a-zA-Z_]*)})');
Matcher myMatch = myPattern.matcher(emailTemplate);
System.debug('\n\nMatch found? ' + myMatch.matches() + '\n\n');

while (myMatch.find()) {			
	System.debug('\n\nStart index: ' + myMatch.start() + '\nEnd index: ' + myMatch.end() + '\n' + myMatch.group() + '\n\n');
}

 

Anup JadhavAnup Jadhav

Hi Alex,

 

Why are the merge fields inside the quotation mark(s), and not outside? I f you move them outside the quotation mark like so

 

Lead lead = [SOQL to retrriev the lead record];
'Dear '+lead.FirstName+', '+
'Thank you for responding to your exclusive invitation.'

 You don't need to use the complex regular expression bit.

 

Anup

Alex.AcostaAlex.Acosta

Because based on certain critera different templates will be used, and to avoid having to redeploy code into prod as many times as possible I figured having an email template serve as a the medium for the scripts being used. This approach also seemed best just because any changes needed to be made and would not require a developer.

 

The original concept was just to simulate as though I had already pulled out the body / header of an email template and work on from that point forward. This is the main reason why you see a string in the example code.

 

I know in other languages and template generators you can pass in your object instances and it will show you the output result, pretty much how when you test out templates within Salesforce, I'm just trying to replicate this logic without having to send an email within APEX.

Anup JadhavAnup Jadhav

Ah I see. Makes sense!

 

Anup

Alex.AcostaAlex.Acosta

So anyone have any ideas of how to appoarch this? Or if some sort of functionality which isavaliable that does this already?

Juan SpagnoliJuan Spagnoli

I created an Apex Class to manage template merge field replacing:

 

public class TemplateResolver{
    public static String paymentFields(String emailTemplate, String recordID){
        return replace(emailTemplate, 'mlsales__Payment__c', recordID);
    }

    public static String userFields(String emailTemplate, String recordID){
        return replace(emailTemplate, 'User', recordID);
    }
    
    private static String replace(String emailTemplate, String objectName, String recordId){
        Pattern regex = Pattern.compile('\\{!([^}]*)\\}');
        Matcher regexMatcher = regex.matcher(emailTemplate);
        Set<String> tokens = new Set<String>();

        while (regexMatcher.find()){         
            String dirtyVariable = regexMatcher.group();
            
            /* Extract curly braces and exclamation marks*/
            String variable = dirtyVariable.substring(2,dirtyVariable.length()-1);
            
            //keep only Lead fields
            if(variable.startsWith(objectName + '.')){
            //remove self-referencing in fieldnames
                tokens.add(variable.replace(objectName + '.', ''));
            }
        }

        //Build dynamic query
        String qry = 'Select ';
        for(String s : tokens){
            qry += s + ',';
        }
        
        //remove last ","
        qry = qry.substring(0, qry.length()-1);
        
        //Do the query
        SObject o = Database.query(qry + ' From ' + objectName + ' Where ID = :recordID');
        
        //Replace values
        for(String s : tokens){         
            emailTemplate = emailTemplate.replace('{!' + objectName + '.' + s + '}', getValue(o, s));
        }
        
        return emailTemplate;
    }
    
    private static String getValue(SObject o, String fieldName){
        return (o.get(fieldName) != null) ? String.valueOf(o.get(fieldName)) : '';
    }

}

 

The main idea is to have different static methods for each object to being replaced. For example:

 

String emailTemplate = 'Dear {!Lead.FirstName}, Thank you for responding to your exclusive invitation. Blah blah blah your ';
emailTemplate += 'Your company name is {!Lead.Company}\n';
emailTemplate += 'Regards,\n{!User.FirstName} {!User.LastName}\n';

emailTemplate = TemplateResolver.leadFields(emailTemplate, '00QE000000CLVhr');
emailTemplate = TemplateResolver.userFields(emailTemplate, UserInfo.getUserId());

//Result
system.debug(LoggingLevel.INFO, '>>>>>>>> ' + emailTemplate);

 The output result is: 

 

10:26:50:110 USER_DEBUG [12]|INFO|>>>>>>>> Dear Kristen, Thank you for responding to your exclusive invitation. Blah blah blah your Your company name is Aethna Home Products
10:26:50:000 USER_DEBUG Regards,
10:26:50:000 USER_DEBUG Juan Spagnoli

 This class can be improved creating a better method for casting fields to strings:

 

private static String getValue(SObject o, String fieldName){
        return (o.get(fieldName) != null) ? String.valueOf(o.get(fieldName)) : '';
}

 

String.valueOf(o.get(fieldName)) <<<<<< For example, a better way to convert a Datetime to a particular formated string.

 

Hope It help you!

Good luck, Juan.