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
Laxmi Pandey 20Laxmi Pandey 20 

Email with collated opportunities per owner after meeting certain criteria

Need some guidance or a piece of code for the below mentioned scenario,

everyday at certain time, lets say at 9 am I want to send an email to opportunity owners with all their opportunities where amount is updated to 20000. so if one owner has 20 opportunity and has 20000 amount in each, then it will collate all these opportunity with their name and amount field and frame one email and send to the owner.

Please help me with the code if possible..
 
Christan G 4Christan G 4
Hi Lax, currently I am writing code to fulfill this requirement. Below is the code that I have written so far. Please note that I haven't had a chance to test it yet. I plan to test by tomorrow hopefully. If you have any questions or concerns, please feel free to reach out to me. I will keep you updated!
 
public class OppEmail implements Schedulable {

    public static void execute(System.SchedulableContext ct) {
        
        List <Opportunity> oppList = [SELECT ID, Name, OwnerID, Amount 
                                      FROM Opportunity 
                                      WHERE Amount = 20000];
        
        Map <Id,User> userMap = new Map <Id, User>([SELECT FirstName FROM User]);
        
        List <Opportunity> ownerOpp = new List <Opportunity>();
        
        Map <ID, List<Opportunity>> oppOwnerMap = new Map <Id, List<Opportunity>>();
        
        for (Opportunity oneOpp : oppList) {
        ownerOpp.clear();
            
            for (Integer i = 0; i < oppList.size(); i++) {
 
                if (oneOpp.OwnerId == oppList[i].OwnerId) {
                    
                    ownerOpp.add(oppList[i]);   
                }   
            }
          oppOwnerMap.put(oneOpp.OwnerId, ownerOpp);       
        }
     //Create new e-mail instance   
     Messaging.SingleEmailMessage oppEmail = new Messaging.SingleEmailMessage();
     
     List <ID> oppOwnerIDs = new List <ID>(oppOwnerMap.keyset());
        
        for (ID oneOwn : oppOwnerIDs) {
           
            List <ID> emailRecipients = new List <ID>{oneOwn};
            
            //Email Settings
            oppEmail.setSenderDisplayName('Salesforce Report');
            oppEmail.setToAddresses(emailRecipients);
            oppEmail.setSubject('Opportunity Records with Amount: $200,000');
            oppEmail.setReplyTo(emailRecipients[0]);
            
            
            String emailBody = 'Dear ' + userMap.get(oneOwn).FirstName + ',';
                   emailBody += ' you currently have ' + oppOwnerMap.get(oneOwn).size() + ' opportunities that have an amount of $200,000.';
                   emailBody += '<br> <br> View Record Details Below: <br>';
            
            List <String> recordOwnerList = new List <String>();
            
            List <Opportunity> relatedOwnerRec = oppOwnerMap.get(oneOwn);
            
            for (Integer i = 0; i < relatedOwnerRec.size(); i++) {
                
                recordOwnerList.add('<li><a href="'+URL.getSalesforceBaseUrl().toExternalForm() +'/'+relatedOwnerRec[i].Id+'">'+ relatedOwnerRec[i].Name +'</a></li>');    

            }
            
            emailBody += recordOwnerList + '<br><br> Thank You';
            oppEmail.setHtmlBody(emailBody);
            
            Messaging.sendEmail(new Messaging.SingleEmailMessage[] {oppEmail});   
        }      
    }
}
Laxmi Pandey 20Laxmi Pandey 20
Thanks Christan.. will try this solution and let you know if it worked... Also, wanted to included an opportunity related object lineitems in the email if they meet certain criteria....Please let me know if that is possible..
Christan G 4Christan G 4
Hi Lax, I am currently debugging the code I wrote and thankfully I just had to tweak only one to two lines. I also made some optimizations elsewhere within it. It should be possible to include opportunity related line items as well if they meet a certain criteria. Almost anything is possible with code so the tricky part will be just writing logic for it. Please tell me the criteria for the line items.

With the code that I have written below, there are a few things to keep in mind:
- Depending on your org, there is a limit as to how many single e-mails can be sent per day. Thus, depending on how many people you think will need to receive an email, we may have to take a different approach.
- Even though the code works, in the test email, I noticed that it only displays a maximum of 10 records.I am trying to find a work around for this.
- Besides code, this may be actually possible through Reports, subscribe method but I have to research more on this.
- If you believe more than 50k records will need to be processed, then we will have to convert the code I wrote into a batch instead.

Feel free to tell me your thoughts.
	List <Opportunity> oppList = [SELECT ID, Name, OwnerID, Amount 
                                      FROM Opportunity 
                                      WHERE Amount = 20000];
        
        Map <Id,User> userMap = new Map <Id, User>([SELECT FirstName, Email FROM User]);
        
        List <Opportunity> ownerOpp = new List <Opportunity>();
        
        Map <ID, List<Opportunity>> oppOwnerMap = new Map <Id, List<Opportunity>>();
        
        for (Opportunity oneOpp : oppList) {
        ownerOpp.clear();
            
            for (Integer i = 0; i < oppList.size(); i++) {
              
                if (oneOpp.OwnerId == oppList[i].OwnerId) {
                    
                    ownerOpp.add(oppList[i]); 
                }   
            }
          oppOwnerMap.put(oneOpp.OwnerId, ownerOpp);  
        }
         
     //Create a list to hold all e-mails 
     List <Messaging.SingleEmailMessage> allEmailMessages = new List <Messaging.SingleEmailMessage>();
        
     //Create new e-mail instance   
     Messaging.SingleEmailMessage oppEmail = new Messaging.SingleEmailMessage();
     
     List <ID> oppOwnerIDs = new List <ID>(oppOwnerMap.keyset());
        
        for (ID oneOwn : oppOwnerIDs) {
           
            List <String> emailRecipients = new List <String>{userMap.get(oneOwn).Email};
            
            //Email Settings
            oppEmail.setSenderDisplayName('Weekly Salesforce Report');
            oppEmail.setToAddresses(emailRecipients);
            oppEmail.setSubject('Opportunity Records with Amount: $20,000');
            oppEmail.setReplyTo(emailRecipients[0]);
            
            
            String emailBody = 'Dear ' + userMap.get(oneOwn).FirstName + ',';
                   emailBody += ' you currently have ' + oppOwnerMap.get(oneOwn).size() + ' opportunities that have an amount of $200,000.';
                   emailBody += '<br> <br> View Record Details Below: <br>';
            
            List <String> recordOwnerList = new List <String>();
            
            List <Opportunity> relatedOwnerRec = oppOwnerMap.get(oneOwn);
            
            for (Integer i = 0; i < relatedOwnerRec.size(); i++) {
                
                recordOwnerList.add('<a href="'+URL.getSalesforceBaseUrl().toExternalForm() +'/'+relatedOwnerRec[i].Id+'">'+ relatedOwnerRec[i].Name +'</a><br>');    

            }
            emailBody += recordOwnerList + '<br><br> Thank You';
            oppEmail.setHtmlBody(emailBody);
            
            allEmailMessages.add(oppEmail);   
        }   
       Messaging.sendEmail(allEmailMessages);
    }
Christan G 4Christan G 4
Hi Lax, yesterday it seems I posted an old version of the code rather than the newest one. My apologies. Below is the correct version. I am still looking into how to include more than 10 record references into an email:
public class OppEmail implements Schedulable {

    public static void execute(System.SchedulableContext ct) {
        
		List <Opportunity> oppList = [SELECT ID, Name, OwnerID, Amount 
                                      FROM Opportunity 
                                      WHERE Amount = 20000];
        
        Map <Id,User> userMap = new Map <Id, User>([SELECT FirstName, Email FROM User]);
        
        List <Opportunity> ownerOpp = new List <Opportunity>();
        
        Map <ID, List<Opportunity>> oppOwnerMap = new Map <Id, List<Opportunity>>();
        
        for (Opportunity oneOpp : oppList) {
        ownerOpp.clear();
            
            for (Integer i = 0; i < oppList.size(); i++) {

                if (oneOpp.OwnerId == oppList[i].OwnerId) {
                    ownerOpp.add(oppList[i]); 
                }   
            }
          oppOwnerMap.put(oneOpp.OwnerId, ownerOpp);     
        }
         
     //Create a list to hold all e-mails 
     List <Messaging.SingleEmailMessage> allEmailMessages = new List <Messaging.SingleEmailMessage>();
        
     //Create new e-mail instance   
     Messaging.SingleEmailMessage oppEmail = new Messaging.SingleEmailMessage();
     
     List <ID> oppOwnerIDs = new List <ID>(oppOwnerMap.keyset());
        
        for (ID oneOwn : oppOwnerIDs) {
           
            List <String> emailRecipients = new List <String>{userMap.get(oneOwn).Email};
            
            //Email Settings
            oppEmail.setSenderDisplayName('Weekly Salesforce Report');
            oppEmail.setToAddresses(emailRecipients);
            oppEmail.setSubject('Opportunity Records with Amount: $20,000');
            oppEmail.setReplyTo(emailRecipients[0]);
            
            
            String emailBody = 'Dear ' + userMap.get(oneOwn).FirstName + ',';
                   emailBody += ' you currently have ' + oppOwnerMap.get(oneOwn).size() + ' opportunities that have an amount of $200,000.';
                   emailBody += '<br> <br> View Record Details Below: <br>';
            
            List <String> recordOwnerList = new List <String>();
            
            List <Opportunity> relatedOwnerRec = oppOwnerMap.get(oneOwn);
            
            for (Integer i = 0; i < relatedOwnerRec.size(); i++) {
                
                recordOwnerList.add('<a href="'+URL.getSalesforceBaseUrl().toExternalForm() +'/'+relatedOwnerRec[i].Id+'">'+ relatedOwnerRec[i].Name +'</a><br>');    

            }
            
            emailBody += recordOwnerList + '<br><br> Thank You';
            oppEmail.setHtmlBody(emailBody);
            
            Messaging.sendEmail(new Messaging.SingleEmailMessage[] {oppEmail});     
        }   
}} 
Laxmi Pandey 20Laxmi Pandey 20
Thanks Christan.. 

There is more to it in the criteria.. so when amount is meeting certain criteria, it should collate emails and send to owners.. Also, it should fire if related object opportunityline item has amount 4000. the complete requirement will as follows:
if only opportunity is meeting criteria it should show only opportunity id,
if line item is meeting the criteria, it should show line item id only....
if an opportunity has amount 20000 and line item has 4000, email should show the opportunity id and the line item id.

anythin on this please.. I really appreciate your assistance in this...
Christan G 4Christan G 4
Okay so just to clarify I understand, these are the conditions for your criteria:

Conditional #1: If an opportunity doesn't have an amount of 20000 (or more - depending on your answer below), but has line items with an amount of 4000, then show only the ids of those line items. 

Quick Question(s): 
1. 
When you say line items, are you referring to the products associated with an opportunity or is this a custom object within your sandbox?

2. Does an opportunity have to equal 20000 exactly or are we considering any opportunity that has an amount equal to or greater than 20000?

3. Does a line item have to equal 4000 exactly or are we considering any line item that has an amount equal to or greater than 4000?

Conditional #2: If an opportunity has an amount of 20000 (or more - depending on your answer above), and it also has line items with an amount of 4000 (or more - depending on your answer above), then show both the opportunity and line item ids. 

Conditional #3: If an opportunity has an amount of 20000 (or more - depending on your answer above), and no line items with an amount of 4000 (or more - depending on your answer above), then show only the opportunity ids. 

Please confirm and answer the questions above
Laxmi Pandey 20Laxmi Pandey 20
Thanks for the assistance Christan.. Below are my answers

1. When you say line items, are you referring to the products associated with an opportunity or is this a custom object within your sandbox?
Ans.. it’s a custom object related with opportunity which has master-detail relationship

2. Does an opportunity have to equal 20000 exactly or are we considering any opportunity that has an amount equal to or greater than 20000?

Ans. It is equal to 20000.

3. Does a line item have to equal 4000 exactly or are we considering any line item that has an amount equal to or greater than 4000?

Ans.  Line items which has amount equal to 4000.
 
Laxmi Pandey 20Laxmi Pandey 20
Hi Christan,

Anything on this request please...
Christan G 4Christan G 4
Hey Lax, so sorry for the late response. I started working on this but haven’t had the chance to finish. I hope to finish my end of today.
Christan G 4Christan G 4
Hi Lax, I hope you are well. Unfortunately, after updating the code to include the line item records and testing it out, it seems sending the email via HTML has a lot of limitations. There is a character limit in regards to how many characters can be included in the body of an email. When that limit is reached, Salesforce truncates the data and only sends a small portion of it. Thus, I have to find an alternative route and most likely start over. 

Currently, I am investigating if there is a way to render a PDF with all this data and include it as an attachment within an e-mail. If this is possible, would this be something that you would like to try? Please note that this may take some time to develop since there would be multiple parts to it most likely.

Also, does your company use Lightning? If yes, there may be a possibility to achieve this through the use of a lightning component. Thankfully, I know flows support both classic and lightning so I plan on exploring as to what they can do in this situation also. I believe they also have the ability to send emails.

So I know you may be asking, is there a temporary workaround in the meantime. Well, thankfully, I think I found one. With reports, you can subscribe to receive an email copy of them if certain conditions are met. Thus, what you can do is create a report with Opportunities that have an Amount equal to $20,000 and another with Line Items that have an Amount equal to $4000. Save both of these records in a public folder and then subscribe to them. When you subscribe to a report, specify as to when you would like to receive an e-mail copy of them. Before receiving the email, the report would autorun to auto-update itself. You can specify to only receive an email when there is at least 1 record within the report to prevent spam. Then, you can specify who you would like to receive this email. It can be particular users, groups, roles or roles and their subordinates. Those who receive the e-mail will be able to view the report and the records the belong to them which meet the criteria that you mentioned. I was wondering if you were aware of this feature and if you think this would be beneficial? 

I apologize again for the wait and I look forward to hearing back from you soon!
Christan G 4Christan G 4
Hi Laxmi, I hope you are well. Over the past few days, I have been working on a solution for this requirement which I hope you'll like. Here is how it works.

1 - Schedule an Apex class called "OppEmailScheduler" to send an email to only internal users who have at least one opportunity record with an amount equal to $20,000 or at least one Line Item record with amount equal to $4,000.

2 - When the user receives an email, it will include a message and a link to view a Visualforce page called, "OppReport". When the user logs in to the view the page, they will be presented with a report that showcases a list of all opportunities and line items that they own and meet the criteria specified above. Thus, each user would have their own individual report to work with. At the moment, the visualforce page can display up to 50k records.

Please provide me your thoughts on this approach. If you believe this would fulfill your requirement, then I will provide the code. Thank you in advance!
Laxmi Pandey 20Laxmi Pandey 20
Hi Christian, I have been working on this.. just wanted to check with you, how will it work when we have an additional condition, let's say when stage is identify or qualification.. I want to send email saying here are the list of opportunities with identify stage, and other lists which fulfill amount and qualification stage conditions .. looking forward to your reply.. thank you
Laxmi Pandey 20Laxmi Pandey 20
This looks good to me.. please share the code
Christan G 4Christan G 4
Hi Laxmi, I hope you are well. I truly apologize for the late response. I have been quite busy. Please copy/paste and follow the instructions that I provided below. 

Step #1 - Save in a separate Apex Class: Opportunity Report Schedulable Email Code - This code is responsible for sending an email out to specific internal users that have an opportunity or line item that fulfills the requirement.
global class oppEmailSchedule implements Schedulable {

   global void execute(SchedulableContext ct) {
        
       List <String> emailUsr = new List <String>();
       List <ID> usrIDs = new List <ID>();
       Map <ID, User> usrMap = new Map <ID, User>([SELECT ID, Name, Email FROM User]);

       //Please replace Opportunity__c and Opportunity__r with the API fieldname of your Opportunity lookup field 
       //within the Line Item Object.
       List <Opportunity> oppList = [SELECT ID, Name, OwnerID, Amount FROM Opportunity WHERE Amount = 20000];
       List <Line_Item__c> LineItemList = [SELECT ID, Name, Opportunity__c, Opportunity__r.OwnerID, Amount__c
                                           FROM Line_Item__c WHERE Amount__c = 4000];
       
       
       
       for (Opportunity opp : oppList) {
           
           if (!usrIDs.contains(opp.OwnerId)) {
              usrIDs.add(opp.OwnerID); 
           } 
       }

           for (Line_Item__c oneLine : LineItemList) {
               
            if (!usrIDs.contains(oneLine.Opportunity__r.OwnerId)) {
               
              usrIDs.add(oneLine.Opportunity__r.OwnerId);
               
           }    
       }
       
       for (Id oneUsrID : usrIDs) {
       
           //Creating email
           Messaging.SingleEmailMessage oppEmail = new Messaging.SingleEmailMessage();
           oppEmail.setTargetObjectId(oneUsrID);
           oppEmail.setSubject('Weekly Salesforce Report');
            oppEmail.setSaveAsActivity(false);
           
           //Creating HTML Body Message
           String emailBody = 'Good Morning all, I hope you are well. <br/><br/>';
           
           emailBody += 'You are receiving this message because you either have an opportunity record with an amount equal to $20,000';
           emailBody += ' or line item record with an amount equal to $4,000.<br/><br/>';
           emailBody += 'Please click on the link below to view a list of all these records: <br/>';
           emailBody += '<a href="'+ URL.getSalesforceBaseUrl().toExternalForm() +'/apex/OppReport">Opportunity and Line Item Report</a><br/><br/>';
           emailBody += 'Thank You';
       
           oppEmail.setHtmlBody(emailBody);
           oppEmail.setSenderDisplayName('Salesforce');
    
           Messaging.sendEmail(new Messaging.SingleEmailMessage[] {oppEmail});   
        }
    }
}

Step #2 - Save the following code into a separate Apex Class - This is the controller code for the Visualforce page to display information.
public class OppEmail_Controller {

    public static ID usr = Userinfo.getUserId();
    public static List <Opportunity> oppList = [SELECT ID, Name, Amount, OwnerID 
                                             FROM Opportunity 
                                             WHERE Amount = 20000 AND OwnerID =:usr];
    
    public static Map <ID,Opportunity> oppMap = new Map <ID, Opportunity>(oppList);

    public static Map <Id,User> usrMap = new Map <Id, User>([SELECT ID, Name FROM User]); 

    //Please replace Opportunity__c and Opportunity__r with the API fieldname of your Opportunity lookup field
    //within the Line Item Object. 
    public static List <Line_Item__c> oppLineItems = [SELECT ID, Name, Opportunity__c, Amount__c, Opportunity__r.Name, Opportunity__r.OwnerID 
                                                  FROM Line_Item__c
                                                  WHERE Amount__c = 4000 AND Opportunity__c IN:oppMap.keySet() AND Opportunity__r.OwnerID =:usr];
    
    
    
    public static void setRecOver(){}
    public static boolean getRecOver(){
        
    boolean overRec = false;
        
        if ( (oppList.size() + oppLineItems.size()) > 50000) {
            
            overRec = true;
        }
        
      return overRec;
        
    }
    
    
    public static void setOwnName() {}
    public static String getOwnName() {
    
    String usrName = usrMap.get(usr).Name;
        
        return usrName;
        
    }
    
    public static void setOppList() {}
    public static List <Opportunity> getOppList() {
        
        return oppList;
        
    }
    
    public static void setNumOfOpp(){}
    public static integer getNumOfOpp() {
        
        return oppList.size();
        
    }
    
    public static void setNumOfLine(){}
    public static integer getNumOfLine() {
        
        return oppLineItems.size();
        
    }
    
    
    public static void setLineRen(){}
    public static boolean getLineRen() {
        
    boolean renSwitch = false;
        
        if (oppLineItems.size() > 0) {
            
            renSwitch = true;
        }
        
        return renSwitch;
        
    }
    
    public static void setOppRen(){}
    public static boolean getOppRen() {
        
    boolean renSwitch = false;
        
        if (oppList.size() > 0) {
            
            renSwitch = true;
        }
        
        return renSwitch;
        
    }
    
  
    public static void setOppLineList() {}    
    public static List <Line_Item__c> getOppLineList() {
        
        return oppLineItems;
             
    }
    
    
    public static void setTotalRec() {}
    public static integer getTotalRec() {
        
      integer total = opplist.size()+oppLineItems.size();
        
      return total;    
 
    }
}

Step #3 - Save the following code into a new Visualforce Page. This is the page that will be presented to the user when they click on the link within the email.
<apex:page controller="OppEmail_Controller" sidebar="false" readOnly="True">
    <style>
    .center{
    text-align:center;
    }
    </style>
    <apex:form >
            <apex:pageBlock title="Report for: {!OwnName}">
                <h3><apex:outputText rendered="{!OppRen}">Your Combined Total Line Items and Opportunity Records: {!TotalRec}</apex:outputText></h3><br/><br/>
                <apex:outputText rendered="{!RecOver}"><h3>Only 50K records can be displayed. To view the rest, please create a report.</h3><br/><br/></apex:outputText>
                <h3><apex:outputText rendered="{!OppRen}">Your Opportunities with Amount: $20,000</apex:outputText></h3><br/>
                <h4><apex:outputText rendered="{!OppRen}">Total Opportunity Records: {!NumOfOpp}</apex:outputText></h4><br/><br/>
                <apex:pageBlockTable value="{!OppList}" var="opp" rendered="{!OppRen}">
                    <apex:column width="100" headerValue="Opportunity Name" headerClass="center" styleClass="center">
                        <apex:outputLink value="/{!opp.id}" target="_blank">{!opp.Name}
                        </apex:outputLink>
                    </apex:column>
                    <apex:column value="{!opp.id}" width="100" headerClass="center" styleClass="center" />
                    <apex:column value="{!opp.Amount}" width="100" headerClass="center" styleClass="center" />
                </apex:pageBlockTable><br/><br/>

                <h3><apex:outputText rendered="{!LineRen}" >Your Line Items Opportunities with Amount: $4,000</apex:outputText></h3><br/>
                <h4><apex:outputText rendered="{!LineRen}">Total Line Item Records: {!NumOfLine}</apex:outputText></h4><br/><br/>
                <apex:pageBlockTable value="{!OppLineList}" var="LineItem">
                    <apex:column width="100" headerValue="Line Item Name" headerClass="center" styleClass="center" rendered="{!LineRen}">
                        <apex:outputLink value="/{!LineItem.id}" target="_blank">{!LineItem.Name}
                        </apex:outputLink>
                    </apex:column>
                    <apex:column value="{!LineItem.id}" width="100" headerClass="center" styleClass="center" />
                    <apex:column value="{!LineItem.Opportunity__r.Name}" width="100" headerClass="center" styleClass="center" headerValue="Related Opportunity" rendered="{!LineRen}" />
                    <apex:column value="{!LineItem.Amount__c}" width="100" headerClass="center" styleClass="center" />
                </apex:pageBlockTable>
            </apex:pageBlock>
    </apex:form>
</apex:page>

Step #4 (Optional) - Save the following code into a separate Apex class. This code is a duplicate of the code stated within the schedule apex class you created earlier. It is used solely for testing purposes. When you want to execute it, navigate to Developer Console, click on "Open Execute Anonymous Block"  under the "Debug" tab and execute the following a code: oppEmailScheduleTest.sendOppEmail(); - Please note all users with Line Items and Opportunities with the amount criteria will be sent an e-mail with a link to view the VF page where they will see all their records.
public class oppEmailScheduleTest {

      public static void sendOppEmail() {
        
       List <String> emailUsr = new List <String>();
       List <ID> usrIDs = new List <ID>();
       Map <ID, User> usrMap = new Map <ID, User>([SELECT ID, Name, Email FROM User]);
       List <Opportunity> oppList = [SELECT ID, Name, OwnerID, Amount FROM Opportunity WHERE Amount = 20000];
       List <Line_Item__c> LineItemList = [SELECT ID, Name, Opportunity__c, Opportunity__r.OwnerID, Amount__c
                                           FROM Line_Item__c WHERE Amount__c = 4000];
       
       
       
       for (Opportunity opp : oppList) {
           
           if (!usrIDs.contains(opp.OwnerId)) {
               
              usrIDs.add(opp.OwnerID);
               
           } 
       }
           
       
           for (Line_Item__c oneLine : LineItemList) {
               
            if (!usrIDs.contains(oneLine.Opportunity__r.OwnerId)) {
               
              usrIDs.add(oneLine.Opportunity__r.OwnerId);
               
           }    
       }
       
       for (Id oneUsrID : usrIDs) {
       
           //Creating email
           Messaging.SingleEmailMessage oppEmail = new Messaging.SingleEmailMessage();
           oppEmail.setTargetObjectId(oneUsrID);
           oppEmail.setSubject('Weekly Salesforce Report');
            oppEmail.setSaveAsActivity(false);
           
           //Creating HTML Body Message
           String emailBody = 'Good Morning all, I hope you are well. <br/><br/>';
           
           emailBody += 'You are receiving this message because you either have an opportunity record with an amount equal to $20,000';
           emailBody += ' or line item record with an amount equal to $4,000.<br/><br/>';
           emailBody += 'Please click on the link below to view a list of all these records: <br/>';
           emailBody += '<a href="'+ URL.getSalesforceBaseUrl().toExternalForm() +'/apex/OppReport">Opportunity and Line Item Report</a><br/><br/>';
           emailBody += 'Thank You';
       
           oppEmail.setHtmlBody(emailBody);
           oppEmail.setSenderDisplayName('Salesforce');
       
           Messaging.sendEmail(new Messaging.SingleEmailMessage[] {oppEmail});   
        }
    }
}
In regards to your question for when additional conditions may be required, I can potentially have users filter the results on the VF page using the stage picklist. Would something like this or did you have something else in mind?

Feel free to inform you if you have any issues within code above. Sorry again for the late reply!
Laxmi Pandey 20Laxmi Pandey 20
Hi Christan,
Thank you for the great support in this.
It seems to be working fine. But I also want to show the opportunity and line item records in email with a hyperlink on their record IDs, and the overall report link so that if they dont want to go in salesforce they can see records in the email itself. anything on this please. thank you.