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
Rakshith RamachandraRakshith Ramachandra 

Writing an apex class and test class to schedule daily email whenever a condition is applicable

I need to write a apex batch class and schedulable class to run every day which sends a email notification using an email template. The condition is that whenever LastModifiedDate field from Opportunity field is less a year from today the email needs to be sent to the opportunity owner

Here's what I've come up with so far.

Batch class -
global class BatchInactiveOpps implements Database.Batchable<sObject> {

    global Database.QueryLocator start(Database.BatchableContext BC)
    {
        return Database.getQueryLocator([SELECT CloseDate,Description,Id,LastModifiedDate FROM Opportunity WHERE LastModifiedDate < LAST_N_DAYS:365]);
    }

    global void execute(Database.BatchableContext BC, List<Opportunity> scope)
    {
    	List<Messaging.SingleEmailMessage> mailsToSend = new List<Messaging.SingleEmailMessage>();
        for(Opportunity opp:scope){
			//TBD
			EmailTemplate template = [SELECT id FROM EmailTemplate WHERE DeveloperName = 'Opportunity_about_to_expire_template'];
			Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
            mail.setTemplateId(template.Id);
            mail.saveAsActivity = false;
            mailsToSend.add(mail);
            System.debug(opp.Name);
        }
        //Send Email
		if(mailsToSend.size() > 0){
    		Messaging.sendEmail(mailsToSend);       
		}
    }
    
    global void finish(Database.BatchableContext BC)
    {
    }
}

Schedulable class
global class SchedulableInactiveOpps implements Schedulable
{
    global void execute(SchedulableContext sc)
    { 
		Id InactiveOpps=Database.executeBatch(new BatchInactiveOpps());
    }
}

Test class
@isTest(SeeAllData=true)
public class TestemailonDuedate {
	public static testMethod void unitTest(){
		Test.startTest();
		EmailTemplate template = [SELECT id FROM EmailTemplate WHERE DeveloperName = 'Opportunity_about_to_expire_template'];
		Task tsk=new Task();
			tsk.ActivityDate=System.Today();
			tsk.Subject='Test';
			tsk.Status='In Progress';
			tsk.Priority='Normal';
			Insert tsk;
			System.assertEquals(tsk.Subject,'Test');

			emailonDuedate emailSch = new emailonDuedate();
			String sch = '0 0 23 * * ?'; 
			System.schedule('Test Territory Check', sch, emailSch); 
		Test.stopTest(); 
	}

}
Opportunity_about_to_expire_template is the email template i want to use while sending the email. 

Please let me know what changes needs to be done to the batch class and test class to make it work. 
Abhilash Mishra 13Abhilash Mishra 13

what is the issue ?  its with the code. or you are not able to schedule the class.  to schedule it
you just need to  execute system.schedule method in anonymous window. or there is a option in the apex classes 

 

thatheraherethatherahere
Hi Rakshith,

You need to make change in your Batch class at line number 13. Never execute a query inside FOR loop. This can hit to SOQL limits. 

Here is the Updated Code:
 
global class BatchInactiveOpps implements Database.Batchable<sObject> {

    global Database.QueryLocator start(Database.BatchableContext BC)
    {
        return Database.getQueryLocator([SELECT CloseDate,Description,Id,LastModifiedDate FROM Opportunity WHERE LastModifiedDate < LAST_N_DAYS:365]);
    }

    global void execute(Database.BatchableContext BC, List<Opportunity> scope)
    {
    	List<Messaging.SingleEmailMessage> mailsToSend = new List<Messaging.SingleEmailMessage>();
        EmailTemplate template = [SELECT id FROM EmailTemplate WHERE DeveloperName = 'Opportunity_about_to_expire_template'];
        for(Opportunity opp:scope){
			Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
            mail.setTemplateId(template.Id);
            mail.saveAsActivity = false;
            mailsToSend.add(mail);
            System.debug(opp.Name);
        }
        //Send Email
		if(mailsToSend.size() > 0){
    		Messaging.sendEmail(mailsToSend);       
		}
    }
    
    global void finish(Database.BatchableContext BC)
    {
    }
}

I hope It will help you.

Thanks,
Govind Thathera
Rakshith RamachandraRakshith Ramachandra
Thanks both of you. I just wanted to know if there is any problem/bugs with the code. Also if I'm missing any logic like 
1. Who gets the email (Only the specific opportunity owner should get the alert
2, Should I write anything in the finish method.
3. Do I need to anything else in the @test method.

I'm new to APex coding. Any help is appreciated

​Thanks
Abhilash Mishra 13Abhilash Mishra 13
Hi, Rakshith
you are not specifying the sender. you have to use setTagetObjectid( id) to send mail to the specific person

here is a fragment of code I once wrote to send email to all the contacts who have their bithdays. you can relate from it

Let me know this helps
for (contact myContact :birthdays) {
                        if (myContact.Email != null && myContact.Name != null) {
                            Messaging.SingleEmailMessage mail =   new Messaging.SingleEmailMessage();
                               mail.setReplyTo(userinfo.getUserEmail());
                               mail.setSenderDisplayName(userinfo.getname());
                                //list<string> ccTo= new list<string>();
                               //ccTo.add(usercc);
                               mail.setCcAddresses(ccTo);
                               mail.setTargetObjectId(myContact.id); 
                                if(bdaytemplate !=null){
                                    mail.setTemplateId(bdaytemplate);   
                                    mails.add(mail);
                                   
                                    }
                                     
                        }
                    }
                }