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>());

Messaging.SingleEmailMessage mail = = new Messaging.SingleEmailMessage();
OrgWideEmailAddress owe = [SELECT ID,DisplayName,Address FROM OrgWideEmailAddress WHERE DisplayName = 'Support'];
// Build email content and To addresses
   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.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.
  • are you OK with using VF email?
    – cropredy
    Apr 7, 2022 at 0:25
  • @cropredy This is in a scheduled batch job so emails are sent once in a month
    – Jenina
    Apr 7, 2022 at 1:37
  • Yes but can the email be a VF email template rather than hard-coded html?
    – cropredy
    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
    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
    Apr 7, 2022 at 2:52

1 Answer 1


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>();
  // 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)) {
     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) {}
  • 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
    Apr 7, 2022 at 3:59
  • That is what my solution does. See openTasksByUserId.
    – cropredy
    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
    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
    Apr 7, 2022 at 4:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.