I'm battling my way through learning Apex, and have created an email trigger for new Events posted in our organization's calendar. I think I have it right (it's still in our sandbox so I can't see what the finished email looks like), but it's sending an alert for all events on all calendars, public and individual.
My question is – Is there a way to limit the alerts to one specific calendar? We'd ideally only like the alerts for our public calendar that has the whole team added to it.
Here is my code for reference:
trigger Event_Email on Event (before insert)
{
String[] toAddresses = new String[] {'name@email.com'};
String[] ccAddresses = new String[] {'name@email.com'};
User userIds = [select id from User where Alias = 'names'];
system.debug(userIds.id);
Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
EmailTemplate et=[Select id from EmailTemplate where name = :'New Event'];
System.debug('New Event'+et);
mail.setTemplateId('00XK0000000QoCj');
mail.setToAddresses(toAddresses);
mail.setCcAddresses(ccAddresses);
mail.setReplyTo('name@email.com');
mail.setSenderDisplayName('Calendar Alert');
mail.setBccSender(false);
mail.setUseSignature(false);
Event eve = trigger.new[0];
mail.setTargetObjectId(userIds.Id);
mail.saveAsActivity = false;
Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
}
Best Answer
Since you cannot access the public calendar Id from Apex (that I could find) you need to go to the public calendar of interest and find it in the URL.
So for example, if you go to the public calendar of interest in the UI and look at the address bar you should look for the Id after cal_lkid. Here's an example of where you might look below:
Here's another example of what it will look like via screenshot:
The 023 and the trailing 12 characters(totaling to 15 characters) will be the public calendar's Id.
Please Note
Once you have that, you need to find a way to access it in Apex. You can either use a custom label or you can use a custom setting. In my approach, I used a custom label (since there is only one public calendar of interest).
When you create your custom label, all you need is a description, the value (the Id found in the URL), and a name to access it (I named mine PublicCalendarOfInterest for my example).
This is what the setup for my custom label looks like:
Once you create your custom label, you can access it through Apex anywhere. Here's how I would do it...
First, I'll create an Apex class to handle my trigger logic:
As you can see, I filtered the Event list by the OwnerId being equal to the custom label (which I casted as an Id). This specifies that the given Event is for that public calendar. Once I find all the Events, regardless of how many, I build an e-mail for each (Apex Limits may apply).
I made sure to handle my events in bulk instead of operating on a single event. It is 99% of the time considered best practice and it scales better in the long run. It is considered a good habit to always develop your triggers for bulk operations, regardless of how many records you expect to operate on. Think of it as future-proofing your work.
I also added a custom exception that I can throw in case certain conditions are not met. Although it is not necessary, this is great for pinpointing any problems that may occur down the line. For example, if you deployed to a higher environment and the user you wanted to notify was not in the system. You could even provide a back-up user if you assured it was consistent in all organizations.
From there, you can hook this up to your trigger code like this:
Testing This Code
Now I have to test it to get it to work. I actually found a simple error in my code (Single E-mail Message not being initialized), which shows why testing your code is such a good idea in the first place. Everyone makes mistakes, but simple tests like these will help you catch those mistakes. Here is the test code to do that:
The testing goes with a very simple happy path scenario (a path where everything goes right). Following the Arrange-Act-Assert pattern, I first setup my data in the tests, run the actual test within Test.startTest and Test.stopTest (in our case, since it is a before trigger test, I placed in the INSERT), and lastly, asserted the results.
You notice that I have two simple assert statements to clarify:
Please note: Regardless of how many e-mails are sent in this test (how many events are inserted), the amount of e-mail invocations will still be one since the sendEmail method is only called once.
You should always put your Act portion of your code between startTest and stopTest blocks since it gives that code separate limits (from what I understand). I also do the try/catch portion around the code to at the very least, assert that the code won't throw an error.
Some final caveats you should know are that the Custom Label, User, and E-mail Template must be available in your org BEFORE you run your tests. Otherwise, this test will fail and no deploy for you. The other thing is that the E-mail Template must be active before running the test. Otherwise it will bomb your test too.