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
SFDCU$erSFDCU$er 

Trigger Help: Too many code statements 200001

I have created an opportunity trigger to send out an email to two separate email address field whenever the stage is Closed Won depending on the Campaign Type. It works perfectly fine but recently when I tried updating a list of 200 opportunity records it gave me an error saying "**Too many code statements 200001**".

 

My code is as follows:

 

trigger SendEmail on Opportunity (after update)
{
Set<Id> accountSet = new Set<Id>();
Set<Id> marketSet = new Set<Id>();

for (Opportunity o : Trigger.new) {
accountSet.add(o.Accountid);
marketSet.add(o.Campaignid);
}
Map<Id, Account> accountMap = new Map<Id, Account>([SELECT Name, Phone, PersonMobilePhone, PersonEmail from Account where id in :accountSet] );
map<Id, Campaign> marketMap = new Map<Id, Campaign>([SELECT Name, Parent_Market__c from Campaign where id in :marketSet]); 
for (Opportunity o : Trigger.new) {
if(o.Campaign_Type__c != Null && o.StageName != Null){
for (Integer i = 0; i < Trigger.old.size(); i++) {
Opportunity old = Trigger.old[i];
Opportunity nw = Trigger.new[i];
Account theAccount = accountMap.get(o.AccountId);
Campaign Market = marketMap.get(o.CampaignId);
String userName = UserInfo.getUserName();

Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage(); 
List<String> toAddresses = new List<String>();
List<String> ccAddresses = new List<String>();
ccAddresses.add('test@test.com');
mail.setToAddresses(toAddresses); 
mail.setCcAddresses(ccAddresses);
mail.setSenderDisplayName('Campaign Information');

mail.setSubject(+ theAccount.Name + ' is Closed Won');

mail.setReplyTo('noreply@salesforce.com');
//Body of the Email
mail.setHtmlBody(
'<font face="Times" size="3">'+
'<table width="100%">'+
'<tr width="0%">'+
'<td rowspan="0">'+
'</td>'+
'<td>'+
'<h2>Account is closed won notification</h2>'+
'</td>'+
'</tr>'+
'</table>'+
'<br/>'+
'<b>Stage:</b> ' + o.StageName + '<br/>' + '<br/>' +
'<b>Opportunity Number:</b> ' + o.Name + '<br/>' +
'<b>Amount Paid:</b> $' + o.Amount + '<br/>' + '<br/>' +
'<b>Account Name:</b> ' + theAccount.Name + '<br/>' +
'<b>Phone:</b> ' + theAccount.Phone + '<br/>' +
'<b>Mobile:</b> ' + theAccount.PersonMobilePhone + '<br/>'+
'<b>Email:</b> ' + theAccount.PersonEmail + '<br/>'+
);

// Send Email if it isCampaign1 and Closed Won
if((nw.StageName !=old.StageName) || (nw.Campaign_Type__c !=old.Campaign_Type__c)){ 
if(o.Campaign_Type__c.equals('Campaign1')){
if(o.StageName.equals('Closed Won') ){
toAddresses.add(o.Email__c);
try {
Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
}
catch(Exception ex) { }
}

}
}
// Send Email if it is Campaign2 and Closed Won
if((nw.StageName !=old.StageName) || (nw.Campaign_Type__c !=old.Campaign_Type__c)){ 
if(o.Campaign_Type__c.equals('Campaign2')){
if(o.StageName.equals('Closed Won')){
toAddresses.add(o.Email2__c);
toAddresses.add(o.Email1__c);
try {
Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
}
catch(Exception ex) { }
}
}
} 
} 
}
} 
}

 

Any help would be appreciated.

Thanks

Best Answer chosen by SFDCU$er
crop1645crop1645

Your problem is here:

 

for (Opportunity o : Trigger.new) {
if(o.Campaign_Type__c != Null && o.StageName != Null){
for (Integer i = 0; i < Trigger.old.size(); i++) {

 For each of the 200 Oppos in Trigger.new, you are looking through each of the Oppos in Trigger.old. Potentially, this is 200 * 200 = 40,000 passes through your code so it is easy to see how you would hit 200,000 script statements.

 

You need to take  advantage of the other Trigger variables, specifically Trigger.oldMap.  That is, for Opportunity o, you can find its old value in Trigger.oldMap.get(o.id)

All Answers

AsitM9AsitM9
You can reduce your batch size.(batch size 200 to 100 ).
crop1645crop1645

Your problem is here:

 

for (Opportunity o : Trigger.new) {
if(o.Campaign_Type__c != Null && o.StageName != Null){
for (Integer i = 0; i < Trigger.old.size(); i++) {

 For each of the 200 Oppos in Trigger.new, you are looking through each of the Oppos in Trigger.old. Potentially, this is 200 * 200 = 40,000 passes through your code so it is easy to see how you would hit 200,000 script statements.

 

You need to take  advantage of the other Trigger variables, specifically Trigger.oldMap.  That is, for Opportunity o, you can find its old value in Trigger.oldMap.get(o.id)

This was selected as the best answer
SFDCU$erSFDCU$er

Thank you Eric for your response. I changed my code to what you have mentioned. It works well but as I said I need to send out emails to two different email ids, Email__c if Campaign type is Campaign1 and Email1__c and Email2__c if Campaign type is Campaign2. Now I am not able to achieve that. It only sends out an email to the ccaddresses and not to the toAddresses now.

crop1645crop1645

YnaTp1 - 

 

Well, this would be an entirely different problem

 

1. I suggest you use System.debug statements to verify your logic as you can then inspect values prior to the sendEmail().

2. Note there are limits on how many APEX outbound emails you can send per day.  Consult the SFDC Limits documents.  If you run afoul of these, a workaround is to update an SObject and then use workflows with email alerts to send the emails. They are less affected by Governor limits