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
Sreenivasulu AdipudiSreenivasulu Adipudi 

Sending an email alert from Batch class finish method

Hi Everyone,

I created a Batch apex to process bulk records. Once the batch process is completed then need to send an email alert. For that, I implemented the following logic on the finish method.
//Query the AsyncApexJob object to retrieve the current job's information.
AsyncApexJob apexJob = [SELECT Id, Status, NumberOfErrors, JobItemsProcessed, TotalJobItems, CreatedBy.Email
FROM AsyncApexJob WHERE Id =: BC.getJobId()];
            
//Send an email to the Apex job's submitter notifying of job completion.
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
String[] toAddress = new String[] {apexJob.CreatedBy.Email};
mail.setToAddresses(toAddress);
mail.setSubject('Apex Job status is ' + apexJob.Status);
mail.setPlainTextBody('The batch Apex job processed ' + apexJob.TotalJobItems + ' batches with '+ apexJob.NumberOfErrors + ' failures.');
Messaging.SingleEmailMessage[] messages = new List<Messaging.SingleEmailMessage> {mail};
Messaging.SendEmailResult[] results = Messaging.sendEmail(messages);

But I didn't get the email alert.
I verified the debug logs, it displays the following message.

|results|"common.apex.runtime.impl.ScalarList@bac8ad2"|0x1ef0e446.
Can anyone please help me.
Thanks in advance.
 
Best Answer chosen by Sreenivasulu Adipudi
abhishek singh 497abhishek singh 497
Hello I tried the below code by replacing the modifications in my org. 

global class BatchJob implements Database.Batchable<sobject>
{
    global Database.QueryLocator start(Database.BatchableContext BC)
    {
        return Database.getQueryLocator([SELECT Id FROM Account]);
    }
    
    global void execute(Database.BatchableContext BC, List<SObject> lstRecords)
    {
        //To hold the list of error messages
        List<Error_Tracking__c> lstErrorTracking = new List<Error_Tracking__c>();
        Error_Tracking__c objErrorTracking;            //To hold an error message
        
        //To perform bulk delete operation
        Database.DeleteResult[] result = Database.delete(lstRecords, false);
        
        //Iterating the result
        for(Database.DeleteResult res : result)
        {
            //If status is not success then create error record and insert it into Error_Tracking__c object
            if(!res.isSuccess())
            {
                for(Database.Error err : res.getErrors())
                {
                    objErrorTracking = new Error_Tracking__c();
                    objErrorTracking.Name = res.getId();
                    objErrorTracking.Error_Message__c = err.getMessage();
                    lstErrorTracking.add(objErrorTracking);
                }
            }
        }
        
        if(lstErrorTracking != Null && lstErrorTracking.size() > 0)
        {
            Database.insert(lstErrorTracking,false);
        }
    }
    global void finish(Database.BatchableContext BC) 
    {
        //Query the AsyncApexJob object to retrieve the current job's information.
        AsyncApexJob apexJob = [SELECT Id, Status, NumberOfErrors, JobItemsProcessed, TotalJobItems, CreatedBy.Email
                                FROM AsyncApexJob WHERE Id =: BC.getJobId()];
        
        //Send an email to the Apex job's submitter notifying of job completion.
        Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
        String[] toAddress = new String[] {apexJob.CreatedBy.Email};
            system.debug('apexJob.CreatedBy.Email : '+apexJob.CreatedBy.Email);
        mail.setToAddresses(toAddress);
        mail.setSubject('Apex Job status is ' + apexJob.Status);
        mail.setPlainTextBody('The batch Apex job processed ' + apexJob.TotalJobItems + ' batches with '+ apexJob.NumberOfErrors + ' failures.');
        //Messaging.SingleEmailMessage[] messages = new List<Messaging.SingleEmailMessage> {mail};
         //   Messaging.SendEmailResult[] results = Messaging.sendEmail(messages);
         Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
        /*
        system.debug('results : '+results);
        if (!results.get(0).isSuccess()) {
            System.StatusCode statusCode = results.get(0).getErrors()[0].getStatusCode();
            String errorMessage = results.get(0).getErrors()[0].getMessage();
        }*/
    }
}
 

All Answers

abhishek singh 497abhishek singh 497
Can you please post your whole code.!!
abhishek singh 497abhishek singh 497
Hello System admin 641,
Please replace below 2 lines in your code :-
Messaging.SingleEmailMessage[] messages = new List<Messaging.SingleEmailMessage> {mail};
Messaging.SendEmailResult[] results = Messaging.sendEmail(messages);

Replace by below line:-
Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });

Please let me know if the solution helps you and please do mark it as best answer.
Thanks ,
Abhishek Singh.
Sreenivasulu AdipudiSreenivasulu Adipudi
I need to delete records from an object by clicking on a button. I am calling a Batch job from the Visualforce controller.
Please find the below code :

global class BatchJob implements Database.Batchable<sobject>
{
    global Database.QueryLocator start(Database.BatchableContext BC)
    {
        return Database.getQueryLocator([SELECT Id FROM Account]);
    }
    
    global void execute(Database.BatchableContext BC, List<SObject> lstRecords)
    {
        //To hold the list of error messages
        List<Error_Tracking__c> lstErrorTracking = new List<Error_Tracking__c>();
        Error_Tracking__c objErrorTracking;            //To hold an error message
        
        //To perform bulk delete operation
        Database.DeleteResult[] result = Database.delete(lstRecords, false);

        //Iterating the result
        for(Database.DeleteResult res : result)
        {
               //If status is not success then create error record and insert it into Error_Tracking__c object
            if(!res.isSuccess())
            {
                for(Database.Error err : res.getErrors())
                {
                    objErrorTracking = new Error_Tracking__c();
                    objErrorTracking.Name = res.getId();
                    objErrorTracking.Error_Message__c = err.getMessage();
                    lstErrorTracking.add(objErrorTracking);
                }
            }
        }
        
        if(lstErrorTracking != Null && lstErrorTracking.size() > 0)
        {
            Database.insert(lstErrorTracking,false);
        }
    }
    global void finish(Database.BatchableContext BC) 
    {
        //Query the AsyncApexJob object to retrieve the current job's information.
           AsyncApexJob apexJob = [SELECT Id, Status, NumberOfErrors, JobItemsProcessed, TotalJobItems, CreatedBy.Email
                                  FROM AsyncApexJob WHERE Id =: BC.getJobId()];
            
            //Send an email to the Apex job's submitter notifying of job completion.
            Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
            String[] toAddress = new String[] {apexJob.CreatedBy.Email};
            system.debug('apexJob.CreatedBy.Email : '+apexJob.CreatedBy.Email);
            mail.setToAddresses(toAddress);
            mail.setSubject('Apex Job status is ' + apexJob.Status);
            mail.setPlainTextBody('The batch Apex job processed ' + apexJob.TotalJobItems + ' batches with '+ apexJob.NumberOfErrors + ' failures.');
            Messaging.SingleEmailMessage[] messages = new List<Messaging.SingleEmailMessage> {mail};
            Messaging.SendEmailResult[] results = Messaging.sendEmail(messages);
                
            system.debug('results : '+results);
            if (!results.get(0).isSuccess()) {
                System.StatusCode statusCode = results.get(0).getErrors()[0].getStatusCode();
                String errorMessage = results.get(0).getErrors()[0].getMessage();
            }
        }
    }
}
Sreenivasulu AdipudiSreenivasulu Adipudi
Hello Abhishek Singh,

Thanks for your quick reply.
I modified the code as per your suggestion. Still, I am facing the same error.
abhishek singh 497abhishek singh 497
Hello I tried the below code by replacing the modifications in my org. 

global class BatchJob implements Database.Batchable<sobject>
{
    global Database.QueryLocator start(Database.BatchableContext BC)
    {
        return Database.getQueryLocator([SELECT Id FROM Account]);
    }
    
    global void execute(Database.BatchableContext BC, List<SObject> lstRecords)
    {
        //To hold the list of error messages
        List<Error_Tracking__c> lstErrorTracking = new List<Error_Tracking__c>();
        Error_Tracking__c objErrorTracking;            //To hold an error message
        
        //To perform bulk delete operation
        Database.DeleteResult[] result = Database.delete(lstRecords, false);
        
        //Iterating the result
        for(Database.DeleteResult res : result)
        {
            //If status is not success then create error record and insert it into Error_Tracking__c object
            if(!res.isSuccess())
            {
                for(Database.Error err : res.getErrors())
                {
                    objErrorTracking = new Error_Tracking__c();
                    objErrorTracking.Name = res.getId();
                    objErrorTracking.Error_Message__c = err.getMessage();
                    lstErrorTracking.add(objErrorTracking);
                }
            }
        }
        
        if(lstErrorTracking != Null && lstErrorTracking.size() > 0)
        {
            Database.insert(lstErrorTracking,false);
        }
    }
    global void finish(Database.BatchableContext BC) 
    {
        //Query the AsyncApexJob object to retrieve the current job's information.
        AsyncApexJob apexJob = [SELECT Id, Status, NumberOfErrors, JobItemsProcessed, TotalJobItems, CreatedBy.Email
                                FROM AsyncApexJob WHERE Id =: BC.getJobId()];
        
        //Send an email to the Apex job's submitter notifying of job completion.
        Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
        String[] toAddress = new String[] {apexJob.CreatedBy.Email};
            system.debug('apexJob.CreatedBy.Email : '+apexJob.CreatedBy.Email);
        mail.setToAddresses(toAddress);
        mail.setSubject('Apex Job status is ' + apexJob.Status);
        mail.setPlainTextBody('The batch Apex job processed ' + apexJob.TotalJobItems + ' batches with '+ apexJob.NumberOfErrors + ' failures.');
        //Messaging.SingleEmailMessage[] messages = new List<Messaging.SingleEmailMessage> {mail};
         //   Messaging.SendEmailResult[] results = Messaging.sendEmail(messages);
         Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
        /*
        system.debug('results : '+results);
        if (!results.get(0).isSuccess()) {
            System.StatusCode statusCode = results.get(0).getErrors()[0].getStatusCode();
            String errorMessage = results.get(0).getErrors()[0].getMessage();
        }*/
    }
}
 
This was selected as the best answer
Sreenivasulu AdipudiSreenivasulu Adipudi
Hello Abhishek Singh,

Thank you for your Answer. It is working fine now.