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
Ria SharmaRia Sharma 

Batch class to send email notification

I tried writing a batch class but I am having hard time adding one condition. Can someone look and help me out. My requirement is below:
1. Run batch apex on daily basis to send email notification 
2. Email should be send 30 days, 60 days and 90 days before contract end date on opportunity where stage is 8 
3. Email should go to only those contacts in associated account where 'sendemail' checkbox is true. 

Now my problem is how to add third condition and how to send email to contact email address. 
 
global class RenewalEmailNotification implements Database.Batchable < sObject >, Schedulable, Database.Stateful { global List<String> errorMessages = new List<String>(); global Database.QueryLocator start(Database.BatchableContext bc) { /* Date d = Date.today();*/ Date ed = Date.today().addDays(30); System.debug(Date.today().addDays(30)); // This set will hold the Id's of the opportunities Set <ID> OppIds = new Set <ID>(); // Query all the Opportunities in your database that meet the selection criterial for update. //List <Opportunity> oppsToUpdate = new List <Opportunity>([SELECT Id FROM Opportunity]); List <Opportunity> oppsToUpdate = new List <Opportunity>([SELECT Id, StageName FROM Opportunity WHERE StageName IN ('8 Renewal', '8 Renewal (pending validation)', '8 Renewal (validated)', '8 Renewal (Quote Delivered to Customer)') AND Contract_End_Date__c=: ed]); // Return this list of opportunities, which will get passed to our execute() method below. return Database.getQueryLocator('Select id, Name , Owner.Email, Contract_End_Date__c FROM opportunity WHERE Id IN: oppsToUpdate '); } global void execute(Database.BatchableContext bc, List < opportunity > recs) { List < Messaging.SingleEmailMessage > mailList = new List < Messaging.SingleEmailMessage > (); for (opportunity c: recs) { if (c.Account != null) { List < String > toAddresses = new List < String > (); Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage(); toAddresses.add(c.Account.name); toAddresses.add(c.Owner.Email); mail.setToAddresses(toAddresses); mail.setSubject('Notification Before 30 Days of Contract End Date'); String messageBody = '<html><body>Hi ' + c.Name + ',<br>Your Contract Expires within 30 Days . <br>Kindly take approriate action.<br><br><b>Regards,</b><br>RV</body></html>'; mail.setHtmlBody(messageBody); mailList.add(mail); } } Messaging.sendEmail(mailList); } global void finish(Database.BatchableContext bc) { AsyncApexJob aaj = [Select Id, Status, NumberOfErrors, JobItemsProcessed, MethodName, 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[] toAddresses = new String[] {aaj.CreatedBy.Email}; mail.setToAddresses(toAddresses); mail.setSubject('JOB Salesforce RenewalEmailNotification Finished: ' + aaj.Status); String bodyText='Total Job Items ' + aaj.TotalJobItems + ' Number of records processed ' + aaj.JobItemsProcessed + ' with '+ aaj.NumberOfErrors + ' failures.\n'; bodyText += 'Number of Error Messages ' + errorMessages.size() + '\n'; bodyText += 'Error Message' + String.join(errorMessages, '\n'); mail.setPlainTextBody(bodyText); Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail }); } global void execute(SchedulableContext SC) { RenewalEmailNotification batchable = new RenewalEmailNotification(); database.executebatch(batchable); } }

 
Sharath KrishnarajSharath Krishnaraj
Hi Ria,

You need to firstly query contacts. I have tweaked your code slightly to help you 

List<String> listOfAccountIds = new List<String>();
for (opportunity c: recs) { 
if (c.Account != null) {
    listOfAccountIds.add(c.accountId);
}
}
 //query contacts belonging to the chosen accounts where "sendemail" = true
 for(Contact c : [select Id, Email from Contact where AccountId IN : listOfAccountIds AND SendEmail__c = true]{
 //send single emails to these contacts
 }
Ria SharmaRia Sharma
Thanks Sharath. I tried adding your code and got below. Can you check if I am missing anything. 
global class RenewalEmailNotification implements Database.Batchable < sObject >, Schedulable, Database.Stateful {
	global List<String> errorMessages = new List<String>();
    global Database.QueryLocator start(Database.BatchableContext bc) {
        /* Date d = Date.today();*/
        Date ed = Date.today().addDays(30);
        System.debug(Date.today().addDays(30));
         // This set will hold the Id's of the opportunities 
        Set <ID> OppIds = new Set <ID>(); 
        
        // Query all the Opportunities in your database that meet the selection criterial for update.
        //List <Opportunity> oppsToUpdate = new List <Opportunity>([SELECT Id FROM Opportunity]);
        List <Opportunity> oppsToUpdate = new List <Opportunity>([SELECT Id, StageName FROM Opportunity WHERE StageName IN ('8 Renewal', '8 Renewal (pending validation)', '8 Renewal (validated)', '8 Renewal (Quote Delivered to Customer)') AND Contract_End_Date__c=: ed]);
        
        // Return this list of opportunities, which will get passed to our execute() method below.
	    return Database.getQueryLocator('Select  id, Name , Owner.Email, Contract_End_Date__c FROM opportunity  WHERE Id IN: oppsToUpdate ');
    }
    
    
global void execute(Database.BatchableContext bc, List < opportunity > recs) {
   
     List<String> listOfAccountIds = new List<String>();
for (opportunity o: recs) { 
if (o.Account != null) {
    listOfAccountIds.add(o.accountId);
}
}
 //query contacts belonging to the chosen accounts where "sendemail" = true
 for(Contact c : [select Id, Email from Contact where AccountId IN : listOfAccountIds AND SendEmail__c = true])
         {
 //send single emails to these contacts
 List < Messaging.SingleEmailMessage > mailList = new List < Messaging.SingleEmailMessage > (); 
                List < String > toAddresses = new List < String > ();
                Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
                toAddresses.add(c.Email);
				//toAddresses.add(o.Owner);
                mail.setToAddresses(toAddresses);
                mail.setSubject('Notification Before 30 Days of Contract End Date');
                String messageBody = '<html><body>Hi ' + c.Name  + ',<br>Your  Contract Expires within 30 Days . <br>Kindly take approriate action.<br><br><b>Regards,</b><br>RV</body></html>';
                mail.setHtmlBody(messageBody);
                mailList.add(mail);
            }
        
        Messaging.sendEmail(mailList);
    }

    global void finish(Database.BatchableContext bc) {
		AsyncApexJob aaj = [Select Id, Status, NumberOfErrors, JobItemsProcessed, MethodName, 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[] toAddresses = new String[] {aaj.CreatedBy.Email};
        mail.setToAddresses(toAddresses);
        mail.setSubject('JOB Salesforce RenewalEmailNotification Finished: ' + aaj.Status);
        String bodyText='Total Job Items ' + aaj.TotalJobItems + ' Number of records processed ' + aaj.JobItemsProcessed + ' with '+ aaj.NumberOfErrors + ' failures.\n';
        bodyText += 'Number of Error Messages ' + errorMessages.size() + '\n';
        bodyText += 'Error Message' + String.join(errorMessages, '\n');
        mail.setPlainTextBody(bodyText);
        Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
	}
	
	global void execute(SchedulableContext SC) {
        RenewalEmailNotification batchable = new RenewalEmailNotification();
		database.executebatch(batchable);
    }
}

 
Abhishek pande 90Abhishek pande 90
I have some similar requirement where i need to send an email alert before 1 year , 6 months ,3 months, 1 month ,Same day to recipients respectively based on a date field. Please help.

Is it possible to achieve using Process Builder ? or Batch Class in the ultimate solution .