You need to sign in to do that
Don't have an account?

Using Batch Scheduling for mass emails apex
I am wondering how to implement my mass emails so they are scheduled so a batch of 100 is sent out every 30 minutes until all emails are sent out, as it stands I have added in ability to batch send all your emails but due to the limitations of 5,000 emails per day I am looking to develop a work around.
I have managed to add the logic for the process in my SchSentReport class but am struggling to get them working together so that the batches of 100 are processed separately. Thanks
SchSentReport
SendReportPageController
I dont think this class has any relevance on the functionality but added it just incase anyone felt it was relevant.
I have managed to add the logic for the process in my SchSentReport class but am struggling to get them working together so that the batches of 100 are processed separately. Thanks
SchSentReport
global class SchSentReport implements Schedulable{ integer count = 1; public SchSentReport(){ } global void execute(SchedulableContext sc) { //check apex job available in system before run batch if(BatchSendReports.isAvailableApexJob()){ BatchSendReports batch = new BatchSendReports(); Database.executeBatch(batch, 100);//100 because single email allow send 100 records per mail setScheduleNext30mn(); System.debug('Batch No. ' + count + ' Added'); count = count + 1; }else{ System.abortJob(SC.getTriggerId()); } } /** * The shedule will start next 30mn */ public void setScheduleNext30mn(){ SchSentReport sch = new SchSentReport(); String myTime = '0 $1 h do m ? y'; Datetime dt = System.now(); dt = dt.addMinutes(30 * count); //schedule at next 30 minutes System.debug('Batch Time set for :' + dt); myTime=myTime.replace('h', dt.hour()+''); myTime=myTime.replace('do', dt.day()+''); myTime=myTime.replace('m', dt.month()+''); myTime=myTime.replace('y', dt.year()+''); myTime=myTime.replace('$1', dt.minute()+''); System.debug('My Time :' + myTime); System.schedule('SchSentReport', myTime, sch); } }
SendReportPageController
public with sharing class SendReportPageController { public Boolean sendDashboard {get;set;} public Boolean sendLocationCO2Report {get;set;} public Boolean sendGroupCO2Report {get;set;} public Boolean sendPartnerReport {get;set;} public Boolean sendLinkedReport {get;set;} public SendReportPageController(){ sendDashboard = false; sendLocationCO2Report = false; sendGroupCO2Report = false; sendPartnerReport = false; sendLinkedReport = false; } public PageReference doSend(){ if(!sendDashboard && !sendLocationCO2Report && !sendGroupCO2Report && !sendPartnerReport && !sendLinkedReport){ Apexpages.Message msg = new Apexpages.Message(ApexPages.Severity.ERROR, 'You have to select at least a report type!'); Apexpages.addMessage(msg); return null; } String msgVal = ''; Boolean isSent = false; if(BatchSendReports.isAvailableApexJob()){ BatchSendReports batch = new BatchSendReports(); batch.sendDashboard = sendDashboard; batch.sendLocationCO2Report = sendLocationCO2Report; batch.sendGroupCO2Report = sendGroupCO2Report; batch.sendPartnerReport = sendPartnerReport; batch.sendLinkedReport = sendLinkedReport; Database.executeBatch(batch, 100);//100 because single email allow send 100 records per mail msgVal = 'Sending report is in progress.'; isSent = true; }else{ msgVal = 'Apex job isnot available. Please try again later.'; } Apexpages.Message msg = new Apexpages.Message(isSent ? ApexPages.Severity.CONFIRM : ApexPages.Severity.Warning, msgVal); Apexpages.addMessage(msg); return null; }BatchSendReports
I dont think this class has any relevance on the functionality but added it just incase anyone felt it was relevant.
public class BatchSendReports implements Database.Batchable<sObject>{ private ID accid; private static final String DASHBOARD_TEMP = 'Monthly_Location_Dashboard'; private static final String MONTHLY_TEMP = 'Monthly_Recycling_Report'; private static final String GROUP_TEMP = 'Group_Recycling_Report'; private static final String PARTNER_TEMP = 'Partner_Recycling_Report'; private static final String LINKED_TEMP = 'Linked_Recycling_Report'; private static final String DASHBOARD_REPORT= 'dashboard'; private static final String MONTHLY_REPORT = 'co2 report'; private static final String GROUP_REPORT = 'enqix spreadsheet'; private static final String PARTNER_REPORT = 'partnership co2 report'; private static final String LINKED_REPORT = 'linked account co2 report'; private Map<String, String> mapReportTypeEmailTemplate = new Map<String, String>{ DASHBOARD_REPORT=> DASHBOARD_TEMP, MONTHLY_REPORT => MONTHLY_TEMP, GROUP_REPORT => GROUP_TEMP, PARTNER_REPORT => PARTNER_TEMP, LINKED_REPORT => LINKED_TEMP}; public Boolean sendDashboard {get;set;} public Boolean sendLocationCO2Report {get;set;} public Boolean sendGroupCO2Report {get;set;} public Boolean sendPartnerReport {get;set;} public Boolean sendLinkedReport {get;set;} //for testing public BatchSendReports(ID accid){ this.accid = accid; ////If run from test, default value will true this.sendDashboard = Test.isRunningTest(); this.sendLocationCO2Report = Test.isRunningTest(); this.sendGroupCO2Report = Test.isRunningTest(); this.sendPartnerReport = Test.isRunningTest(); this.sendLinkedReport = Test.isRunningTest(); } public BatchSendReports(){ //If run from test, default value will true this.sendDashboard = Test.isRunningTest(); this.sendLocationCO2Report = Test.isRunningTest(); this.sendGroupCO2Report = Test.isRunningTest(); this.sendPartnerReport = Test.isRunningTest(); this.sendLinkedReport = Test.isRunningTest(); } public Database.QueryLocator start(Database.BatchableContext BC){ Set<String> reportTypes = new Set<String>(); if(sendDashboard) reportTypes.add(DASHBOARD_REPORT); if(sendLocationCO2Report) reportTypes.add(MONTHLY_REPORT); if(sendGroupCO2Report) reportTypes.add(GROUP_REPORT); if(sendPartnerReport) reportTypes.add(PARTNER_REPORT); if(sendLinkedReport) reportTypes.add(LINKED_REPORT); String query = 'Select Name, Main_Contact_Email__c, Report_Type__c From Account '; String condition = ' Where Report_Type__c != null AND Report_Type__c in:reportTypes ' + (accid != null ? ' AND id=:accid ' : '') ; return Database.getQueryLocator(query + condition); } public void execute(Database.BatchableContext BC, List<sObject> scope){ //get all related email templates Map<String, String> mapEmailTemplates = new Map<String, String>(); for (EmailTemplate et : [SELECT Id, DeveloperName FROM EmailTemplate WHERE DeveloperName in:mapReportTypeEmailTemplate.values()]) { mapEmailTemplates.put(et.DeveloperName, et.Id); } //get all Contacts related Account that its Receive_Global_Report__c = true Map<String, List<String>> mapAccConGlobalReport = new Map<String, List<String>>(); for(Contact con: [Select Email, AccountId From Contact Where Receive_Global_Report__c = true AND Email != null AND AccountID in: (List<Account>) scope]) { if(!mapAccConGlobalReport.containsKey(con.AccountId)){ mapAccConGlobalReport.put(con.AccountId, new List<String>()); } mapAccConGlobalReport.get(con.AccountId).add(con.Email); } List<OrgWideEmailAddress> orgWilds = [Select Id From OrgWideEmailAddress Where DisplayName ='First Mile' AND IsAllowAllProfiles = true limit 1]; List<Messaging.SingleEmailMessage> lstMails = new List<Messaging.SingleEmailMessage>(); List<ResultReportSent__c> lstRecordResults = new List<ResultReportSent__c>(); for(Account acc: (List<Account>) scope){ String reportType = acc.Report_Type__c.toLowerCase(); Boolean isGeneratePDF = mapReportTypeEmailTemplate.containsKey(reportType) && !mapReportTypeEmailTemplate.get(reportType).equalsIgnoreCase(DASHBOARD_TEMP); Boolean isGroup = reportType.equalsIgnoreCase(GROUP_REPORT); Boolean isPartner = reportType.equalsIgnoreCase(PARTNER_REPORT); Boolean isLinked = reportType.equalsIgnoreCase(LINKED_REPORT); //get email template by Account report type String emailTemp = mapReportTypeEmailTemplate.containsKey(reportType) ? mapReportTypeEmailTemplate.get(reportType) : ''; if(emailTemp == '') continue; String emailTemplateId = mapEmailTemplates.containsKey(emailTemp) ? mapEmailTemplates.get(emailTemp) : ''; if(emailTemplateId == '') continue; List<String> lstReciptients = new List<String>(); //if Account report type is Dashboard or Monthly report, it required acc.Main_Contact_Email__c if((reportType.equalsIgnoreCase(DASHBOARD_REPORT) || reportType.equalsIgnoreCase(MONTHLY_REPORT)) && acc.Main_Contact_Email__c == null) continue; if(acc.Main_Contact_Email__c != null){ lstReciptients.add(acc.Main_Contact_Email__c); } //when the "Group Recycling Report" or "Partner Recycling Report" OR "Linked Recycled Report" is pressed, //any contacts for that account that "Receive Global Report" checked will get the group report. if((isGroup || isPartner || isLinked) && mapAccConGlobalReport.containsKey(acc.Id)){ lstReciptients.addall(mapAccConGlobalReport.get(acc.Id)); } //record the results by report type of the number sent for each batch lstRecordResults.add(new ResultReportSent__c( Account__c = acc.Id, Status__c = 'Sent', Date_Sent__c = System.today(), Name = System.now().format('MMMM yyyy') + ' Report')); //prepare email lstMails.add(SendingEmailUtils.generateEmail(emailTemplateId, acc.Id, lstReciptients, orgWilds, isGeneratePDF, isGroup, isPartner, isLinked)); } if(!lstMails.isEmpty()){ try { Messaging.sendEmail(lstMails); if(!lstRecordResults.isEmpty()){ insert lstRecordResults; } }catch (Exception ex) { System.debug('****** Error: ' + ex.getMessage()); } } } public void finish(Database.BatchableContext BC){ AsyncApexJob asyn = [Select Status, CreatedBy.Email, TotalJobItems, NumberOfErrors From AsyncApexJob Where id=:BC.getJobId() limit 1]; String[] toAddresses = new String[]{asyn.CreatedBy.Email}; Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage(); mail.setSubject('Batch Sending Report ' + asyn.Status); mail.setPlainTextBody('The batch Apex job processed ' + asyn.TotalJobItems + ' batches with ' + asyn.NumberOfErrors + ' failures.'); mail.setToAddresses(toAddresses); mail.setBccAddresses(new List<String>{/*'customers@thefirstmile.co.uk'*/}); Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail }); } public static Boolean isAvailableApexJob(){ return 5 > [Select count() From AsyncApexJob where Status in ('Processing', 'Preparing')]; } }
Please check with below post from stack exchange community with similar discussion and possible solution.
- http://salesforce.stackexchange.com/questions/153331/using-batch-scheduling-for-mass-emails-apex
May I request you to please close this thread by marking it as solved so that others can get benefited.Regards,
Nagendra.