My requirement is to send email to an Id when there are open tasks which are older than 3 days pertaining to Lead segregated by Region. Email Alert to each region overdue tasks will be sent corresponding email Id. I tried to build an batch Apex for this. Since batch process is been chunked into 200 records, I am struggling to identify a way to send email only once of all the chunks. Now lets say batch process identified 400 over due Task records, at end of the process NA leader should get only one email. I also tried to have AggregateResult query in the scheduler class as,

AggregateResult[] leadresults = [SELECT Count(Id) cou,Execution_Manager_Region__c FROM Lead WHERE Id=: taskIDList AND Status='Open' GROUP BY Execution_Manager_Region__c]

But again I am stuck how to pass this to the batch class to process. What am I missing here?

enter image description here

    ***Scheduler class******
public class expiredTasks_SendEmail_ToMgr_Scheduler implements Schedulable{
  public void execute (SchedulableContext ctx)
    date d = system.today().addDays(-3);

    List<String> taskIDList = new List<String>();
    List<Task>  results = [Select WhoId FROM Task Where Who.Type = 'Lead' AND Owner.IsActive = true
                                        AND Status ='Not Started' AND ActivityDate <=: d AND Who.RecordType.Name='Marketing' ];

    for(Task objTsk: results)

      expiredTasks_SendEmail db = new expiredTasks_SendEmail(taskIDList,'expiredTasks_SendEmail_ToMgr_Scheduler','ExpiredTasks_Due_Email_To_ClientSupport');

    **Batch class****
public class expiredTasks_SendEmail implements Database.Batchable<sObject>{

  public String Templatename;
  public String Jobname,taskOwner;
  public List<String> taskList;
  String query;
  List<string> toAddress = new List<string>();
  public Integer naCount=0;

  public expiredTasks_SendEmail(List<String> objList,String Jobname,String Templatename)
    this.taskList = objList;
    this.Templatename = Templatename;
    this.Jobname = Jobname;

  public database.QueryLocator start(Database.BatchableContext BC){
      query = 'Select Execution_Manager_Region__c from Lead where Id =: taskList AND Status = \'Open\' AND Execution_Manager_Region__c != \'Null\' ';
    return  Database.getQueryLocator(query);


  public void execute(Database.BatchableContext BC, List<sObject> scope)

    if(Jobname=='expiredTasks_SendEmail_ToMgr_Scheduler' )
      List<Messaging.SingleEmailMessage> expiredMgrEmailAlert = new List<Messaging.SingleEmailMessage>();
      Messaging.SingleEmailMessage emailMgrAlert = new Messaging.SingleEmailMessage();    
      OrgWideEmailAddress owe = [SELECT ID,DisplayName,Address FROM OrgWideEmailAddress WHERE DisplayName = 'SFDC Support'];

        for(sObject a: scope)
            if((String)a.get('Execution_Manager_Region__c') == 'NA')
              naCount = 1;
            if(naCount == 1){
              System.debug('execution  Mgr'+(String)a.get('Execution_Manager_Region__c'));
              toAddress.add('[email protected]');
              emailMgrAlert.setSubject('Overdue Lead Follow-up');
              String body = 'Hi there';
              naCount = naCount + 1;

  public void finish(Database.BatchableContext BC)

    // Get the AsyncApexJob that represents the Batch job using the Id from the BatchableContext
    AsyncApexJob a = [Select Id, Status, NumberOfErrors, JobItemsProcessed, TotalJobItems, CreatedBy.Email, ExtendedStatus from AsyncApexJob where Id = :BC.getJobId()];
    // Email the Batch Job's submitter that the Job is finished.
    Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
    String[] toAddresses = new String[] {a.CreatedBy.Email,'[email protected]'};
    mail.setSubject(Jobname+ ':' + a.Status);
    mail.setPlainTextBody('The batch Apex job processed ' + a.TotalJobItems + ' batches with '+ a.NumberOfErrors + ' failures. ExtendedStatus: ' + a.ExtendedStatus);
    Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });

  • Did you look into the database.stateful interface. It will allow you to store ids of those sent across batches
    – Eric
    Sep 12, 2017 at 7:17
  • Database.Stateful, only instance member variables retain their values between transactions. Static member variables don’t retain their values and are reset between transactions. And thats what happening here too. "naCount" variable is resetting on every batch and I am not able to limit the email only once.
    – user28452
    Sep 12, 2017 at 15:15
  • @user28542 - You are not implementing stateful. Try it and you will see the naCount will retain its value. - Do not make it a static variable though, leave it as it is.
    – Eric
    Sep 12, 2017 at 15:53
  • @Eric: Yes having database.stateful and count variable helped! Thanks for your help.
    – user28452
    Sep 27, 2017 at 5:55

1 Answer 1


**1.Use Batch Apex for Task Processing:Continue using batch Apex to process the overdue tasks. This is a good choice for handling a large number of records in chunks. 2. **Aggregate Results in Scheduler Class:In your scheduler class, keep aggregating the results using the SOQL query you mentioned. This will help you count the number of open tasks for each region. 3. Pass Aggregated Results to Batch Class:Once you have the aggregated results in the scheduler class, you can pass this data to the batch class for further processing. You can store the aggregated results in a custom object or a custom setting and then access this data from the batch class. Alternatively, you can pass the aggregated results as a parameter when you start the batch job. 4.Process Aggregated Results in Batch Class:

  • In the execute method of your batch class, you can go through the aggregated results and send email alerts to the corresponding email IDs based on the regions. You can use the Database.executeBatch method to start a new batch job for sending email alerts, passing the relevant data to the new batch job.**
  • 1
    Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.
    – Community Bot
    Sep 22, 2021 at 14:32
  • 1
    I've downvoted this answer because it is a code dump. Explaining the problem and how your solution addresses it is as important as the solution itself.
    – Derek F
    Sep 22, 2021 at 15:14
  • Hi i just posted an updates the answer in above Jan 29 at 13:45

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .