0

I want to send email to user about his open tasks. Each user will have more than one task.

I have a set of taskIds and querying all tasks based on these IDs.

How do I get email address of task owners and send email with list of tasks for each owner.

//Task User Map
Map<ID, List<Task>> tasksByUserMap = new Map<ID, List<Task>>();

// Query all tasks
List<Task> lstReminderTasks = [SELECT ID, Subject, ActivityDate, WhatId, OwnerId, Owner.Email FROM Task WHERE ID IN: taskIds AND Status = 'Open' ]; 

Here's a sample data for the above query:

Sample Data

Owners XYZ and ABC have two tasks each.

//Build Task Owner Map from the list
for(Task task: lstReminderTasks){
List<Task> userTasks = tasksByUser.get(taskRecord.OwnerId);
if(userTasks == null) {
            tasksByUserMap.put(task.OwnerId, userTasks = new List<Task>());
        }
        userTasks.add(task);

}
Messaging.SingleEmailMessage mail = = new Messaging.SingleEmailMessage();
OrgWideEmailAddress owe = [SELECT ID,DisplayName,Address FROM OrgWideEmailAddress WHERE DisplayName = 'Support'];
// Build email content and To addresses
if(!tasksByUserMap.isEmpty())
{
   String[] toaddress;
   htmlBody += 'Below tasks are due : ' + '</br> </br>';
   htmlBody += '<table><tr><th>Task Subject</th><th>Due Date</th><th>Priority</th></tr>'
   for(Task t : lstReminderTasks ) {
    htmlBody += '<tr>';
    htmlBody += '<td>'+ t.Subject +'</td>';
    htmlBody += '<td>'+ t.ActivityDate +'</td>';
    htmlBody += '<td>'+ t.Priority+'</td>';
    htmlBody += '</tr>'
    mail.setOrgWideEmailAddressId(owe.ID);
    mail.setSaveAsActivity(false);
    mail.setToAddresses(toAddress); // How to get toAddress here ? 
    mail.setHtmlBody(htmlBody );
   }

}

I need help with -

  • Refining my code to get the ToAddress based on owner ID
  • Create a data structure / map to send email to owner regarding their tasks only.
5
  • are you OK with using VF email?
    – cropredy
    Commented Apr 7, 2022 at 0:25
  • @cropredy This is in a scheduled batch job so emails are sent once in a month
    – Jenina
    Commented Apr 7, 2022 at 1:37
  • Yes but can the email be a VF email template rather than hard-coded html?
    – cropredy
    Commented Apr 7, 2022 at 1:40
  • We need the values dynamically based on the query in the batch job. My issue is not with the email template , its with creating a list of "To address" based on tasks owned by each ownerId. @cropredy
    – Jenina
    Commented Apr 7, 2022 at 2:08
  • ignore my VF email comment - I forgot that there is no related list between User and Task - my answer tho addresses this
    – cropredy
    Commented Apr 7, 2022 at 2:52

1 Answer 1

0

Given this is a batch job

public Database.QueryLoactor start(Database.BatchableContext bc) {
   return [SELECT Id, Email
           FROM User];
}

public void execute(Database.BatchableContext bc User[] users) {
    // collect all userIds to find open Tasks
    Map<Id,User> usersById = new Map<Id,User> (users);
    
    // get all Open tasks for these userIds
    Map<Id,Task[] openTasksByUserId = new Map<Id,Task[]>(); 
    for (Task t : [SELECT ...
                     FROM Task
                     WHERE OwnerId IN : usersById.keySet() AND
                           Status = 'Open'] ) {
      if (!openTasksByUserId.containsKey(t.OwnerId)) {
           openTasksByUserId.put(t.OwnerId,new List<Task>();
      }
      opentasksByUserId.get(t.OwnerId).add(t);
    };
             
  // for all users with open Tasks, send email w/ tasks
  for (Id userId: openTasksByUserId.keySet()) {
     Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
     mail.toAddresses = new List<String> {usersById.get(userId).Email};
     String[] displayableTasks = new List<String>();
     for (Task t: openTasksByUserId.get(userId)) {
      displayableTasks.add(htmlMe(t));
     }
     mail.setHtmlBody(displayableTasks);  
     ...
     mail.send();  // there are limits to worry about, you can't send too many emails/day by apex 
  }
}
private String htmlMe(Task t) {
   return someFormnatted HTML based on a Task  
}
public void finish(Database.BatchableContext bc) {}
4
  • Thanks @cropredy Do we need usersById ? I have the queried task owner email address in lstReminderTasks. But not sure how to build the map so that each email lists only task related to that user.
    – Jenina
    Commented Apr 7, 2022 at 3:59
  • That is what my solution does. See openTasksByUserId.
    – cropredy
    Commented Apr 7, 2022 at 4:09
  • Thank you @cropredy, just unsure why we need User[] users and usersById . I have updated my quesion with sample data which already has owner email address as well.
    – Jenina
    Commented Apr 7, 2022 at 4:29
  • Sure, one could but the pattern above is so common that I reuse it over and over again. It arguably is a better separation of concerns pattern than exploiting the owner.email field on the first Task in each list. There is no performance penalty of note to build usersById.
    – cropredy
    Commented Apr 7, 2022 at 4:54

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .