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
LudivineLudivine 

trigger emailAlert on Event

Hi Team,

Currently, I am unable to set up an email alert for the Event object, the standard functionality does not allow you to set up workflow email for Events and Tasks. Only way to overcome that is create a trigger.

I have searched a lot but didn't find how to write this EmailAlert on Event object.
If it is possible, could you show me a sample code to fire an email alert to  "CreatedBy" and "Assigned To" users when End Date of the Event is Overdue ( EndDateTime > Today() ) ?

Many thanks for your help,

Regards,
Ludivine
Best Answer chosen by Ludivine
kevin Carotherskevin Carothers
Hi Syntaxis - try this.   I highlighted the relevant lines of code;

trigger Trigger_Event_Send_Email on Event (before update) {
    Set<Id> ownerIds = new Set<Id>();
    Set<Id> initiatorIds = new Set<Id>();
   
    for(Event evt: Trigger.New)
        ownerIds.add(evt.OwnerId);    //Assigned TO
        
    Map<Id, User> userMap = new Map<Id,User>([select Id, Name, Email from User where Id in :ownerIds]);
  
      for(Event evt: Trigger.New)
        initiatorIds.add(evt.CreatedById);   //Created By
        
    Map<Id, User> userMap2 = new Map<Id,User>([select Id, Name, Email from User where Id in :initiatorIds]);
  

    for(Event evt : Trigger.New)  {
        User theUser = userMap2.get(evt.CreatedById);
        User TheAssignee = userMap.get(evt.ownerId);
        Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
        String[] toAddresses = new String[] {theUser.Email};
        mail.setToAddresses(toAddresses);    // Set the TO addresses
        mail.setSubject('An event owned by you has been updated');    // Set the subject

        String template = 'Hello {0}, \nYour event has been added. Here are the details - \n\n';
        
        template+= 'Subject - {1}\n';
        template+= 'Due Date - {2}\n';
        template+= 'Location - {3}\n';
        String duedate = '';
        template+= 'Assign To - {4}\n';
        template+= 'Type - {5}\n\n';
        template+= 'Link - {6}\n';
        
        if (evt.ActivityDate==null)
            duedate = '';
        else
            duedate = evt.ActivityDate.format();
        
        List<String> args = new List<String>();

        args.add(theUser.Name);
        args.add(evt.Subject);
        args.add(duedate);
        args.add(evt.location);
        args.add(theAssignee.Name);
        args.add(evt.Type);
        args.add('https://'+System.URL.getSalesforceBaseURL().getHost()+'/'+evt.Id);
        
        // Here's the String.format() call.
        String formattedHtml = String.format(template, args);
       
        mail.setPlainTextBody(formattedHtml);
        Messaging.SendEmail(new Messaging.SingleEmailMessage[] {mail});
  
  
    }
}


All Answers

kevin Carotherskevin Carothers

Hi,

I'm just taking a swag at it - this is unchecked code;

trigger Trigger_Event_Send_Email on Event (before update) {
    Set<Id> ownerIds = new Set<Id>();
   
    for(Event evt: Trigger.New)
        ownerIds.add(evt.ownerId);
   
    Map<Id, User> userMap = new Map<Id,User>([select Name, Email from User where Id in :ownerIds]);
    for(Event evt : Trigger.New)  {
        User theUser = userMap.get(evt.ownerId);
        Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
        String[] toAddresses = new String[] {theUser.Email};
        mail.setToAddresses(toAddresses);    // Set the TO addresses
        mail.setSubject('An event owned by you has been updated');    // Set the subject

        String template = 'Hello {0}, \nYour event has been added. Here are the details - \n\n';
        
        template+= 'Subject - {1}\n';
        template+= 'Due Date - {2}\n';
        template+= 'My Test Field - {3}\n';
        String duedate = '';
        
        if (evt.ActivityDate==null)
            duedate = '';
        else
            duedate = evt.ActivityDate.format();
        
        List<String> args = new List<String>();
        args.add(theUser.Name);
        args.add(evt.Subject);
        args.add(duedate);
        args.add(evt.Location);
       
        // Here's the String.format() call.
        String formattedHtml = String.format(template, args);
       
        mail.setPlainTextBody(formattedHtml);
        Messaging.SendEmail(new Messaging.SingleEmailMessage[] {mail});
    }
}

This trigger just fires an email out on creation of an event.

The other requirment of yours is a little trickier - I would think you have to set up a batch apex class that looks for all events with that searcg criteria, and then uses code similar to the above that notifies users.
 
Beware of governor limits regarding emails!

LudivineLudivine
Hi Kevin,

Wahoo fantastic, it works like a charm!

I will see for the Apex class if this is not enough for our users, for the moment It is exactly what I was looking for, many many thanks to you!!
LudivineLudivine
toc toc toc...me again!
Can I ask you how I can retrieve the value in the What field?
Actually, I have the id in the email near " Related To "and I would like to the see text instead.
Thanks again!
kevin Carotherskevin Carothers

Hi Syntaxis,
 

Glad the code is some help to you.

Can you post a picture of what the problem is?  
I having a problem picturing in my mind  what's going on. 

 

LudivineLudivine
Hi Kevin,

Thank you for dealing with my case.
By my question I meant I would like to add the "Related To" (WhatId) field ( from Event form) on the email alert as well.
When I tried to add this field like the others it shows me an error.
How can I retrieve lhe text value of the field ( related To field) in that trigger? thx
trigger Trigger_Event_Send_Email on Event (before update) {
    Set<Id> ownerIds = new Set<Id>();
    Set<Id> initiatorIds = new Set<Id>();
   
    for(Event evt: Trigger.New)
    //Assigned TO
        ownerIds.add(evt.OwnerId);
    Map<Id, User> userMap = new Map<Id,User>([select Name, Email from User where Id in :ownerIds]);
  
      for(Event evt: Trigger.New)
    //Created By
        initiatorIds.add(evt.CreatedById);
    Map<Id, User> userMap2 = new Map<Id,User>([select Name, Email from User where Id in :initiatorIds]);
  

    for(Event evt : Trigger.New)  {
        User theUser = userMap2.get(evt.CreatedById);
        User TheAssignee = userMap.get(evt.ownerId);
        Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
        String[] toAddresses = new String[] {theUser.Email};
        mail.setToAddresses(toAddresses);    // Set the TO addresses
        mail.setSubject('An event owned by you has been updated');    // Set the subject

        String template = 'Hello {0}, \nYour event has been added. Here are the details - \n\n';
        
        template+= 'Subject - {1}\n';
        template+= 'Due Date - {2}\n';
        template+= 'Location - {3}\n';
        String duedate = '';
        template+= 'Assign To - {4}\n';
        template+= 'Type - {5}\n';
        
        if (evt.ActivityDate==null)
            duedate = '';
        else
            duedate = evt.ActivityDate.format();
        
        List<String> args = new List<String>();

        args.add(theUser.Name);
        args.add(evt.Subject);
        args.add(evt.location);
        args.add(duedate);
        args.add(theAssignee.Name);
        args.add(evt.Type);
          
        // Here's the String.format() call.
        String formattedHtml = String.format(template, args);
       
        mail.setPlainTextBody(formattedHtml);
        Messaging.SendEmail(new Messaging.SingleEmailMessage[] {mail});
  
  
    }
}


kevin Carotherskevin Carothers
Hi Syntaxis

There wer just a couple template items that were in the wrong order - and when making a map from a SOQL statement that has the ID as the key, you should select the ID as the first item inthe statement.   Those were the only changes I made and it seems to be working -- give it a shot;

trigger Trigger_Event_Send_Email on Event (before update) {
    Set<Id> ownerIds = new Set<Id>();
    Set<Id> initiatorIds = new Set<Id>();
   
    for(Event evt: Trigger.New)
        ownerIds.add(evt.OwnerId);    //Assigned TO
        
    Map<Id, User> userMap = new Map<Id,User>([select Id, Name, Email from User where Id in :ownerIds]);
  
      for(Event evt: Trigger.New)
        initiatorIds.add(evt.CreatedById);   //Created By
        
    Map<Id, User> userMap2 = new Map<Id,User>([select Id, Name, Email from User where Id in :initiatorIds]);
  

    for(Event evt : Trigger.New)  {
        User theUser = userMap2.get(evt.CreatedById);
        User TheAssignee = userMap.get(evt.ownerId);
        Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
        String[] toAddresses = new String[] {theUser.Email};
        mail.setToAddresses(toAddresses);    // Set the TO addresses
        mail.setSubject('An event owned by you has been updated');    // Set the subject

        String template = 'Hello {0}, \nYour event has been added. Here are the details - \n\n';
        
        template+= 'Subject - {1}\n';
        template+= 'Due Date - {2}\n';
        template+= 'Location - {3}\n';
        String duedate = '';
        template+= 'Assign To - {4}\n';
        template+= 'Type - {5}\n';
        
        if (evt.ActivityDate==null)
            duedate = '';
        else
            duedate = evt.ActivityDate.format();
        
        List<String> args = new List<String>();

        args.add(theUser.Name);
        args.add(evt.Subject);
        args.add(duedate);
        args.add(evt.location);
        args.add(theAssignee.Name);
        args.add(evt.Type);
          
        // Here's the String.format() call.
        String formattedHtml = String.format(template, args);
       
        mail.setPlainTextBody(formattedHtml);
        Messaging.SendEmail(new Messaging.SingleEmailMessage[] {mail});
  
  
    }
}

kevin Carotherskevin Carothers
Oh -BTW.

Including a link to the event, contact, lead, etc   is often a good idea - so when your CSRs get the email via mobile, they can just click on the link and go right to the record, and then click on the phone #  -- it's a great time saver for them.
LudivineLudivine
Hi Kevin,

Yes it's a fantastic idea to add a link to the record instead, how can I do that?
kevin Carotherskevin Carothers
Hi Syntaxis - try this.   I highlighted the relevant lines of code;

trigger Trigger_Event_Send_Email on Event (before update) {
    Set<Id> ownerIds = new Set<Id>();
    Set<Id> initiatorIds = new Set<Id>();
   
    for(Event evt: Trigger.New)
        ownerIds.add(evt.OwnerId);    //Assigned TO
        
    Map<Id, User> userMap = new Map<Id,User>([select Id, Name, Email from User where Id in :ownerIds]);
  
      for(Event evt: Trigger.New)
        initiatorIds.add(evt.CreatedById);   //Created By
        
    Map<Id, User> userMap2 = new Map<Id,User>([select Id, Name, Email from User where Id in :initiatorIds]);
  

    for(Event evt : Trigger.New)  {
        User theUser = userMap2.get(evt.CreatedById);
        User TheAssignee = userMap.get(evt.ownerId);
        Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
        String[] toAddresses = new String[] {theUser.Email};
        mail.setToAddresses(toAddresses);    // Set the TO addresses
        mail.setSubject('An event owned by you has been updated');    // Set the subject

        String template = 'Hello {0}, \nYour event has been added. Here are the details - \n\n';
        
        template+= 'Subject - {1}\n';
        template+= 'Due Date - {2}\n';
        template+= 'Location - {3}\n';
        String duedate = '';
        template+= 'Assign To - {4}\n';
        template+= 'Type - {5}\n\n';
        template+= 'Link - {6}\n';
        
        if (evt.ActivityDate==null)
            duedate = '';
        else
            duedate = evt.ActivityDate.format();
        
        List<String> args = new List<String>();

        args.add(theUser.Name);
        args.add(evt.Subject);
        args.add(duedate);
        args.add(evt.location);
        args.add(theAssignee.Name);
        args.add(evt.Type);
        args.add('https://'+System.URL.getSalesforceBaseURL().getHost()+'/'+evt.Id);
        
        // Here's the String.format() call.
        String formattedHtml = String.format(template, args);
       
        mail.setPlainTextBody(formattedHtml);
        Messaging.SendEmail(new Messaging.SingleEmailMessage[] {mail});
  
  
    }
}


This was selected as the best answer
LudivineLudivine
Hi Kevin,


Great it works fine now! Many many thanks!!
I read that I had to make a test class for code coverage, is it mandatory for triggers ?

kevin Carotherskevin Carothers
Hi Syntaxis,

Try this test class;

@isTest 
public class testemailalert {
 static testmethod void testemailalertmethod() {
   
   List<Profile> userProfile = new List<Profile>([SELECT Id FROM profile WHERE name='System Administrator' ]);
   
   List<UserRole> userrole = new List<UserRole>([select id from UserRole where Name = 'CEO']);
   //data for user object
   User usr = new User(alias = 'standt', email = 'test@9876test.com',  IsActive=true,
                                  emailencodingkey = 'UTF-8', lastname = 'TestLasName', languagelocalekey = 'en_US', 
                                  localesidkey = 'en_US',  UserRoleId=userrole.get(0).id,
                                  ProfileId=userProfile.get(0).Id,
                                  timezonesidkey = 'America/Los_Angeles', username = 'testUniqudeName@test.com');
    insert usr;
    
    System.runAs ( usr ) {
     Account acc = new Account();
     acc.Name = 'Test Account';
     insert acc;
     DateTime dt = DateTime.Now();
     DateTime dt1 = dt.addHours(1);
     Event e = new Event(subject='test', OwnerId=usr.Id, DurationInMinutes=60,
             WhatId = acc.Id, EndDateTime=dt1, StartDateTime=dt);
     insert e;
     e.Subject = 'a subject';
     update e;
     }
  }
}

LudivineLudivine
Thank you very much, It failed to insert the user, I have inactivated the line and I got 71% code coverage on my trigger, it works from me!
Thanks a lot!
LudivineLudivine
Hi!!

I have now an issue with the what ID element on the event form.
it works for Events related to Opportunitunities but it doesn't work for the Events related to an Account
,
I have added the argument in my trigger but there must be a mistake ..
"Error: Invalid Data.
Review all error messages below to correct your data.
Apex trigger Trigger_Event_Send_Email caused an unexpected exception, contact your administrator: Trigger_Event_Send_Email: execution of BeforeUpdate caused by: System.NullPointerException: Attempt to de-reference a null object: Trigger.Trigger_Event_Send_Email: line 41, column 1

Trigger is :
trigger Trigger_Event_Send_Email on Event (before update) {
    Set<Id> ownerIds = new Set<Id>();
    Set<Id> initiatorIds = new Set<Id>();
    Set<Id> OpptyIds = New Set<Id>();
    Set<Id> AccIds = New Set<Id>();

   
    for(Event evt: Trigger.New)
    //Assigned TO
        ownerIds.add(evt.OwnerId);
    Map<Id, User> userMap = new Map<Id,User>([select Name, Email from User where Id in :ownerIds]);
  
    For(Event evt: Trigger.New)
    //Created By
        initiatorIds.add(evt.CreatedById);
    Map<Id, User> userMap2 = new Map<Id,User>([select Name, Email from User where Id in :initiatorIds]);
  
    For(Event evt : Trigger.New)
  //WhatId = Action
        OpptyIds.add(evt.WhatId);
    Map<id, Opportunity> OpptyMap = new Map<Id,Opportunity>([select Name from Opportunity where Id in :OpptyIds]);
    
    For(Event evt : Trigger.New)
  //WhatId = Account
        AccIds.add(evt.WhatId);
    Map<id, Account> AccMap = new Map<Id,Account>([select Name from Account where Id in :AccIds]);
    
    

    for(Event evt : Trigger.New)  {
        User User = userMap2.get(evt.CreatedById);
        User Assignee = userMap.get(evt.ownerId); 
        Opportunity RelatedTo = OpptyMap.get(evt.WhatId);       
        Account RelatedTo2 = AccMap.get(evt.WhatId);       
        Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
        String[] toAddresses = new String[] {Assignee.Email};
        mail.setToAddresses(toAddresses);    // Set the TO addresses
        mail.setSubject('A visit Report owned by you is due soon');    // Set the subject

      String Whatid ; 
       if (RelatedTo.Name == '')
       whatid = RelatedTo2.Name;
       
       if (RelatedTo2.Name == '')
       whatid = RelatedTo.Name;

        String template = 'Hello {0}, \nThe following Visit Report is due soon:\n';
        
        String duedate = '';       
        template+= '\n';
        template+= 'Due Date - {1}\n';
        template+= 'Type - {2}\n';     
        template+= 'Subject - {3}\n';
        template+= 'Assign To - {4}\n';
        template+= 'Related To - {5}\n';   
        template+= '\n';
        template+='Click on the following link to access the Visit Report:\n';
        template+= '{6}\n';
        
        //String duedate = '';
    If(System.now() == evt.Send_Email_Alert__c )   
         evt.SendEmailAlert__c = True;
        if (evt.EndDateTime ==null)
            duedate = '';
        Else
           duedate = evt.EndDateTime.format();
                  
               List<String> args = new List<String>();

        args.add(Assignee.Name);
        args.add(duedate);
        args.add(evt.type);
        args.add(evt.subject);
        args.add(Assignee.Name);
        args.add(whatid);
        args.add('https://'+System.URL.getSalesforceBaseURL().getHost()+'/'+evt.Id);
        
        // Here's the String.format() call.
        String formattedHtml = String.format(template, args);
       
        mail.setPlainTextBody(formattedHtml);
        Messaging.SendEmail(new Messaging.SingleEmailMessage[] {mail});
     
            
            }
    }

many thanks!!