Based on my previous post, CRM is sending appointments automatically to the attendees. But what if you don’t want CRM to send this appointments?
The system itself has no option, to disable this behavior, but there is a workaround. This is not just configurable in CRM but also on Exchange.
How is this working:
- Add information to the appointment, which shows, that this appointment must not be sent.
- Add a rule to exchange, to prevent sending the message.
First we have to write a plugin, that adds a specific information to the appointment-body. In my example, I’ll add the text “—SendNoInvitationToAttendees—„. This text will be added to the end of the body. I’m using a plugin, because if I only use javascript, this text won’t be added, if a user tracks an appointment in outlook.
I added a sample code, which adds the information, if there are attendees:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
using Microsoft.Xrm.Sdk; using System; using System.Text.RegularExpressions; namespace Mittermair.Appointment { /// <summary> /// If a participant is entered in the Required (requiredattendees) or Optional (optionalattendees) field, /// the Text (--- SendNoInivationToAttendees ---) will be added to the description field. /// </summary> public class StopSendingAppointmentInvitations : IPlugin { private const string PreventAttributeText = "---SendNoInvitationToAttendees---"; public void Execute(IServiceProvider serviceProvider) { // getting the context var context = (IPluginExecutionContext)serviceProvider.GetService(typeof(IPluginExecutionContext)); // saving the preimage and input parameter var image = context.PreEntityImages["Target"]; var inputParameter = (Entity)context.InputParameters["Target"]; EntityCollection optionalAttendees = null; EntityCollection requiredAttendees = null; EntityCollection optionalAttendeesFromImage = null; EntityCollection requiredAttendeesFromImage = null; //Checks if data is available in the pre image if (image != null) { optionalAttendeesFromImage = image.GetAttributeValue<EntityCollection>("optionalattendees"); requiredAttendeesFromImage = image.GetAttributeValue<EntityCollection>("requiredattendees"); } //Checks if data is available in the InputParameter if (inputParameter.Contains("optionalattendees")) optionalAttendees = inputParameter.GetAttributeValue<EntityCollection>("optionalattendees"); if (inputParameter.Contains("requiredattendees")) requiredAttendees = inputParameter.GetAttributeValue<EntityCollection>("requiredattendees"); //if there are changes of attendees => check if added or deleted if (optionalAttendees != null || requiredAttendees != null) { if (optionalAttendees != null && optionalAttendees.Entities.Count == 0 && optionalAttendeesFromImage != null && optionalAttendeesFromImage.Entities.Count > 0) { //old attendees should be deleted => so in future no attendees will exist => set variable null optionalAttendees = null; } if (optionalAttendees != null && optionalAttendees.Entities.Count == 0 && optionalAttendeesFromImage != null && optionalAttendeesFromImage.Entities.Count == 0) { //no new added and no old attendees exists = set variable null optionalAttendees = null; } if (requiredAttendees != null && requiredAttendees.Entities.Count == 0 && requiredAttendeesFromImage != null && requiredAttendeesFromImage.Entities.Count > 0) { //old attendees should be deleted => so in future no attendees will exist => set variable null requiredAttendees = null; } if (requiredAttendees != null && requiredAttendees.Entities.Count == 0 && requiredAttendeesFromImage != null && requiredAttendeesFromImage.Entities.Count == 0) { //no new added and no old attendees exists = set variable null requiredAttendees = null; } } else //if there are no changes of attendees use them from image { if (optionalAttendeesFromImage != null && optionalAttendeesFromImage.Entities.Count > 0) { //if there are any optional attendees in image use them optionalAttendees = optionalAttendeesFromImage; } if (requiredAttendeesFromImage != null && requiredAttendeesFromImage.Entities.Count > 0) { //if there are any optional attendees in image use them requiredAttendees = requiredAttendeesFromImage; } } if (optionalAttendees != null || requiredAttendees != null) { // There are optional or required attendees => add text to prevent from sending var description = PreventAttributeText; if (inputParameter.Contains("description")) { description = AddPreventAttributeTextIfNecessary(inputParameter.GetAttributeValue<string>("description")); } else if (image != null) { description = AddPreventAttributeTextIfNecessary(image.GetAttributeValue<string>("description")); } inputParameter["description"] = description; } } /// <summary> /// Compose description and constant text (---SendNoInvitationToAttendees---) /// </summary> /// <param name="description">Text already in the description</param> /// <returns></returns> private static string AddPreventAttributeTextIfNecessary(string description) { // if no description was added by the user, we just add the text. if (string.IsNullOrEmpty(description)) { return PreventAttributeText; } // checking, if the text was already added before var rgx = new Regex(PreventAttributeText); if (!rgx.IsMatch(description)) { return description + "\n\n\n" + PreventAttributeText; } return description; } } } |
Next, we have to register this plugin on the appointment with the following configuration:
- Create
- pre-operation
- Update
- pre-operation
- Filtering Attributes: optionalattendees, requiredattendees, description
- Image
- Parameters: optionalattendees, requiredattendees, description
Now, after adding attendees to the appointment, the text will be added to the end of your description. After saving, CRM will send the appointment. Therefore we need step two. We have to add an exchange rule:
In my case, all users outside of the organization don’t get the appointment.