Steps to reproduce:
- Create Visualforce Email Template
- Create Visualforce component and add it into the email template
- Create Apex Controller for the component from pt.2
- Do some SOQL queries there, process them and result pass into component markup.
- Generate an email using Messaging.renderStoredEmailTemplate many times and get results from the email body. One email template generation takes 1 SOQL query limit, controller SOQL query limits are not counted.
LimitsHack.email
<messaging:emailTemplate subject="Limits Hack" recipientType="User" relatedToType="Contact">
<messaging:plainTextEmailBody>
<c:LimitsHackCmp/>
</messaging:plainTextEmailBody>
</messaging:emailTemplate>
LimitsHackCmp.component
<apex:component id="LimitsHackCmp" controller="LimitsHackCmpController" access="global">
{!results}
</apex:component>
LimitsHackCmpController.cls
public String results {
set;
get {
String result = '';
for (Integer i = 0; i < 100; i++) {
List<Account> accs = [SELECT Name FROM Account LIMIT 1 OFFSET :Math.mod(i, 3)];
result += i + ') ' + accs[0].Name + ' ';
}
return result;
}
}
}
LimitsHackPlayground.cls
public with sharing class LimitsHackPlayground {
public static void execute() {
EmailTemplate emailTmpl = [
SELECT Id
FROM EmailTemplate
WHERE DeveloperName = 'LimitsHack'
];
System.debug(UserInfo.getUserId());
for (Integer i = 0; i < 35; i++) {
Long renderStart = System.now().getTime();
String emailBody = Messaging.renderStoredEmailTemplate(emailTmpl.Id, UserInfo.getUserId(), '<any contact id>').plainTextBody;
System.debug('LimitsHackPlayground: i=' + i + '. Took ' + (System.now().getTime() - renderStart) + ' ms. Email Body: ' + emailBody);
}
}
}
OFFSET :Math.mod(i, 3)
I used to avoid any type of caching because of the deterministic repeatable query. Each email generation takes up to 500ms, so it is easy to get into the Apex CPU time limit. But still, I managed to make 35 email renders.
Question: Is it expected behavior or a bug? Did anybody meet similar behavior before?
Messaging.renderStoredEmailTemplate
is a separate transaction, the per-tx limit of 100 SOQL queries is still good. Does it complain if you go over 100 in the controller?