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
Elwic87Elwic87 

How can I tweak this snippet to send out reminders for past due opportunities? [Batch Apex]

I'm using the following code:


global class SendNotificationBatch implements Database.Batchable<sObject>, Schedulable, Database.Stateful { //Variable Section global FINAL String strQuery; global List<String> errorMessages = new List<String>(); global SendNotificationBatch() { this.strQuery = getBatchQuery(); } //Returns the Query String to Batch constructor to fetch right records. private String getBatchQuery() { String strQuery = 'SELECT Id, CloseDate, Owner.Email FROM Opportunity WHERE CloseDate < TODAY'; return strQuery; } //Batch Start method global Database.QueryLocator start(Database.BatchableContext BC) { return Database.getQueryLocator(strQuery); } //Batch Execute method calls findCostForWoD method global void execute(Database.BatchableContext BC, List<sObject> scopeList) { System.debug(LoggingLevel.INFO, '== scopeList size ==' + scopeList.size()); List<Opportunity> oppList = (List<Opportunity>) scopeList; if(!oppList.isEmpty()) { List<Messaging.SingleEmailMessage> mailList = new List<Messaging.SingleEmailMessage>(); for (Opportunity prod : oppList) { Messaging.SingleEmailMessage message = new Messaging.SingleEmailMessage(); String[] toAddresses = new String[] {prod.Owner.Email}; Message.setToAddresses(toAddresses); Message.SaveAsActivity = false; mailList.add(Message); } if(!mailList.isEmpty()) { try{ Messaging.sendEmail(mailList); } catch (Exception ex) { errorMessages.add('Unable to send email to Tech: '+ ex.getStackTraceString()); } } } } //Batch Finish method for after execution of batch work 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 Send Notification Batch: ' + 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 }); } //Method which schedules the ProductDownloadBatch global void execute(SchedulableContext sc) { SendNotificationBatch snInstance = new SendNotificationBatch(); ID batchprocessid = Database.executeBatch(snInstance); } }

but I get this error when executing:

Error MessageUnable to send email to Tech: Class.SendNotificationBatch.execute: line 41, column 1

I'm assuming it has to do with opportunity products, when I just want to look at the CloseDate field on the Opportunity object. Any ideas on what to change?  Thanks!
Best Answer chosen by Elwic87
Abhishek BansalAbhishek Bansal
Hi ,

As discussed in our call, the issue was that you were missing the required field Body in the email and due to which the batch is failing. After adding the body it was successfull. So please close this question by choosing a best answer.

Thanks,
Abhishek Bansal.

All Answers

ShirishaShirisha (Salesforce Developers) 
Hi,

Greetings!

I would suggest you to capture the debug logs to narrow down the code.Otherwise,please find the sample code in the below thread and make changes accordingly.

https://developer.salesforce.com/forums/?id=906F0000000Ba8oIAC

Please mark it as best answer if it helps you to fix the issue.

Thank you!

Regards,
Shirisha Pathuri
Abhishek BansalAbhishek Bansal
Hi ,

Can you please use the code snippet to paste the class code as it is not readble in this form. If you want we can connect and discuss the solution to your issue.

Thanks,
Abhishek Bansal.
Email: abhibansal2790@gmail.com
Skype: abhishek.bansal2790.
Elwic87Elwic87
global class SendNotificationBatch implements Database.Batchable<sObject>, Schedulable, Database.Stateful { 

//Variable Section global FINAL String strQuery; global List<String> errorMessages = new List<String>(); global SendNotificationBatch() { this.strQuery = getBatchQuery(); } 

//Returns the Query String to Batch constructor to fetch right records. private String getBatchQuery() { String strQuery = 'SELECT Id, CloseDate, Owner.Email FROM Opportunity WHERE CloseDate < TODAY'; return strQuery; } 

//Batch Start method global Database.QueryLocator start(Database.BatchableContext BC) { return Database.getQueryLocator(strQuery); } 

//Batch Execute method calls findCostForWoD method global void execute(Database.BatchableContext BC, List<sObject> scopeList) { System.debug(LoggingLevel.INFO, '== scopeList size ==' + scopeList.size()); List<Opportunity> oppList = (List<Opportunity>) scopeList; if(!oppList.isEmpty()) { List<Messaging.SingleEmailMessage> mailList = new List<Messaging.SingleEmailMessage>(); for (Opportunity prod : oppList) { Messaging.SingleEmailMessage message = new Messaging.SingleEmailMessage(); String[] toAddresses = new String[] {prod.Owner.Email}; Message.setToAddresses(toAddresses); Message.SaveAsActivity = false; mailList.add(Message); } if(!mailList.isEmpty()) { try{ Messaging.sendEmail(mailList); } catch (Exception ex) { errorMessages.add('Unable to send email to Tech: '+ ex.getStackTraceString()); } } } } 

//Batch Finish method for after execution of batch work 

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 Send Notification Batch: ' + 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 }); } 

//Method which schedules the ProductDownloadBatch global void execute(SchedulableContext sc) { SendNotificationBatch snInstance = new SendNotificationBatch(); ID batchprocessid = Database.executeBatch(snInstance); } }

 
Abhishek BansalAbhishek Bansal
Hi ,

Can you please make sure the Email Deliverabilty is set to All Emails in your salesforce org.

Thanks,
Abhishek Bansal.
Elwic87Elwic87
It's set to all email but returns an error. 
Abhishek BansalAbhishek Bansal
Is it possible fo you to connect over a call? I cant see any error in the code.
Elwic87Elwic87
Sure Abhishek - you can give me a ring at (443) 892-2181‬.
 
Abhishek BansalAbhishek Bansal
I am based in India.. Is it possible to connect on skype, google meet or whatsApp?
You can also share zoom link if you want.

Skype: abhishek.bansal2790
WhatsApp: +91-7357512102
Elwic87Elwic87
https://us04web.zoom.us/j/77328166012?pwd=N3lKa3N4MkZjbXh1VUdKekFCZ0o2Zz09 

Passcode: 53XtUt
Abhishek BansalAbhishek Bansal
Hi ,

As discussed in our call, the issue was that you were missing the required field Body in the email and due to which the batch is failing. After adding the body it was successfull. So please close this question by choosing a best answer.

Thanks,
Abhishek Bansal.
This was selected as the best answer
Elwic87Elwic87
Thanks Abhishek! We added NAME to line 13: 
String strQuery = 'SELECT Id, NAME, CloseDate, Owner.Email FROM Opportunity WHERE CloseDate < TODAY';

And the following after line 35:
Message.setPlainTextBody('The following opportunity is past due:' + Opp.Name + ' ' + Opp.CloseDate);

This returned the overdue record's name and it's due date​​​​​​​.