[SalesForce] How to send an email to the Custom Setting Email field value using trigger

I have Name and Email__c fields in Custom Settings Object,
For example :

Name = 'Support' and

Email__C = 'test@gmail.com'.

When ever a case is created with the pick list value "Support"
(which matches the custom setting Name field value) and click on save button then the
case status field value must be updated automatically to 'Closed' and sends
an email to the custom setting Email__c field value (test@gmail.com)

trigger CaseTrigger on Case (before insert, before update)
{    
    List<Case> cases = new List<Case>();   
    for(Case c : Trigger.new)
    {
        if(c.PickList__C== 'Support')
        {
            c.Status='Closed';
            cases.add(c);            
        }
        if(cases.size()>0)
        {
            update cases;
        }
    }
    Custom_Settings__c cs = Custom_Settings__c.getInstance('Support');
    String  CsEmail= cs.Email__C;
    if(CsEmail!= Null)
    {

        String[] toAddresses = new String[] {CsEmail};
        Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
        mail.setToAddresses(toAddresses);
        mail.setSenderDisplayName('Salesforce Support');
        mail.setSubject('New Case Created : ' + case.Id);
        System.debug('case id' +case.id);
        mail.setBccSender(false);
        mail.setUseSignature(false);
        mail.setPlainTextBody('Your Case: ' + case.Id +' has been created.');
        mail.setHtmlBody('Your case:<b> ' + case.Id +' </b>has been created.<p>'+
        'To view your case <a href=https://na1.salesforce.com/'+case.Id+'>click here.</a>');
        mail.setSaveAsActivity(false);
        Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });

    }

}

Please Correct my trigger i am getting below error

Error: Invalid Data.
Review all error messages below to correct your data.
Apex trigger CaseTrigger caused an unexpected exception, contact your administrator: CaseTrigger: execution of BeforeInsert caused by: System.SObjectException: DML statement cannot operate on trigger.new or trigger.old: Trigger.CaseTrigger: line 13, column 1

Best Answer

You can't always perform DML operations (insert, update, delete, etc...) on trigger context variables (trigger.new and the like).

+edit

It is possible to take records from Trigger.new in an After Insert trigger, and call DML update on them. I know, because I'm doing exactly that in some code for my org. The problem you're running into likely stems from attempting to DML update Trigger.new in a block of code that can be reached when your trigger is already running before update

/edit

From that error that you're getting, it appears that Salesforce is also checking whether or not the collection of sObjects you're trying to run DML on exists in a trigger context variable (and complains if they do).

Salesforce is trying to protect you from yourself here. If Salesforce didn't do this, you'd be staring at a 'self reference from trigger' or 'maximum trigger depth exceeded' message instead.

If you are running a trigger before insert or before update, you don't need to run DML. If you modify a record in Trigger.new or Trigger.newMap in a before trigger (before insert or before update), those changes will automatically be saved.

This functionality won't help you out too much in this case though, because this trigger has deeper issues.

you would run into another issue when you try to build your email message. sObjects don't have an Id until after insert.

To fix your trigger, you have two options:

Option 1

  • Change before insert to after insert, and before update to after update
  • Loop through trigger.new, perform your check for cases that should be closed
  • DML update the list of cases that are being changed to 'closed'
    • This should be done outside of your loop
  • Build and send your emails in a block that only executes after update

Option 2

  • Instead of changing the Case status in a trigger, make this a workflow rule with a field update to close your case. You can choose to run this workflow rule on record creation only.
  • Make this trigger fire after update only (since you wouldn't be updating the Case record in your trigger anymore, it's good practice to make it an 'after' trigger)
  • Build and send your emails in a block that only executes after update

You should also bulkify your email sending code. I'd need to do more research into an appropriate solution for this. My first instinct would be to loop through trigger.new, create new Messaging.SingleEmailMessage instances, store them in a list, and then send all the emails once you're outside of the loop.

Related Topic