If there is one piece of an Exchange or Outlook appointment that is as important as it tends to be misunderstood, it would certainly have to be the Organizer property.
This lovely little fellow returns a string which represents the name of the individual who owns the appointment, or, as Microsoft puts it in the Outlook Object Model (OOM) documentation, it is “…the name of the organizer of the appointment.” As helpful as that is, what does it even mean for one to be an organizer of an appointment? I’m going to cover these questions as well as go over why it is very dangerous to rely on this property in your product’s code.
What is an Organizer?
Exchange server protocol documentation defines the organizer as “the owner or creator of a conference or event.”
I hate to contradict official Exchange white papers, but although the organizer is indeed the owner of an event, they are not necessarily always the “creator”. A delegate for a manager can create an appointment on that manager’s calendar, however the delegate will not be marked as the organizer; rather, the manager will be the organizer. You may say, “Well, the delegate carries out actions in the manager’s name.” which is not entirely correct, because a normal delegate actually very much retains their own identity, and this is reflected by some various properties which will reflect the delegate’s name on the appointment.
Let’s do a better job in defining what an organizer is: The organizer of an appointment can be described as the owner of the calendar in which an appointment is first created. By saying “owner of the calendar”, I’m referring to the individual for which the mailbox store containing the calendar belongs to. The organizer is commonly referred to (by Microsoft and others) as the meeting organizer, however it is important to remember that not all appointments are meetings, but all appointments have an organizer. This fact is important in the very definition of what a meeting is, which is an appointment that is extended “…to contain attendees in addition to the organizer.” [MS-OXOCAL - 188.8.131.52]
So what’s the importance of being an organizer? What special privileges or capabilities does one acquire when donning the Organizer cap? What are some important limitations?
- The fact that an individual is an organizer is displayed to attendees in the meeting request; this alone is probably one of the most important consequences of being the organizer, at least as far as day-to-day business dealings are concerned.
- The organizer is the individual that will receive all responses to any meeting requests sent by or through the organizer; that is, unless it has been configured for all responses to go to a delegate instead.
- Once an appointment object has been saved, you cannot change who the organizer is (or so they say). This little factoid is probably one of the first bits of information developers or users may encounter when inquiring about the nature of the appointment’s organizer. In fact, I’ll bet that’s the reason you’re reading this very article.
- Other than some special do’s and don’ts that one must follow when working with appointments in the very low levels of things, there’s really not much else.
While there are certainly other actions an organizer can take that a normal attendee typically cannot (such as adding an attendee, removing an attendee, etc.), all of these types of actions are wholly dependent on the permissions and type of access the individual has in relation to the original appointment item; they have nothing to do with being the organizer. This is why a delegate can do everything an organizer can.
Regardless of the actual limited number of automatic perks that come with being an organizer, many third-party solutions out there tend to use the fact that someone is an organizer as a simple way to see if the user owns and thus can modify/mess around with an appointment. Although nothing is easier than checking if the current user’s name matches the string returned by the Organizer property, this is a dangerous way to proceed for a number of reasons we’ll get into later.
How is the Organizer’s Identity Determined?
Folks who work with Outlook solutions generally refer to the OOM’s Organizer property of an appointment item to determine who the organizer is. As I’ve stated before, this property returns a string representing the name of the organizer. So…is that it then? Is the identity of the organizer persisted through a simple string property on the appointment object? Where does this Organizer property actually get its value?
These are all questions with, surprisingly, unclear answers. While some of the above is addressed by Microsoft on the MSDN, they do not, in particular, (from what I’ve seen) seem to mention the exact origin of the value returned by the Organizer property anywhere.
It takes only simple deduction to realize that Outlook is aware of more about the organizer than simply the name of the organizer. For instance, create a new appointment on your calendar, and then click on the Scheduling Assistant ribbon button in the Show group. You’ll see something similar to the following:
Scheduling Assistant Displaying the Organizer
If you look at the icon next to my name, you’ll that I’m the organizer of the meeting (the icon being the “organizer” icon and all). So, we see that it knows the name of the organizer. Isn’t that what we get by looking at the Organizer property?
Well my friends, you’ll be pleased (horrified) to know, that the name shown in the above picture and the value returned by the Organizer property do not come from the same place. In fact, they are not linked at all, the fact that they tend to be the same value is merely a consequence of actions taken by the client. It is indeed possible for them to differ in value (even if they originally were the same value) as well, however that’s outside the scope of this article.
Back on topic, if we take a closer look at the entry above, we’ll see that Outlook is actually aware of the true identity of the user that is marked as the organizer. You can see this simple by moving your mouse over the name. This will result in something similar to the image below:
Scheduling Assistant Displaying the Organizer + Additional Information
Simply based on the fact that we’re seeing the card pictured above should tell us that we are looking at the user’s actual address entry as well as some other information. Indeed, clicking on one of the icons in the above card will lead us to the user’s contact details.
What does this all tell us? This tells us that Outlook and Exchange are intimately aware of the identity of the organizer of the appointment; they do not rely simply on a literal name for the organizer. They are aware of enough information regarding the organizer to be able to pull the contact information for the user. What does that require? It requires the entry ID of the entry for the user in an address book (i.e. the GAL).
So where is the organizer’s information stored in the appointment, and in what form? Roughly speaking, information regarding the organizer is stored in two separate places, one of them being, in my opinion, the most official of the two as far as what makes some an actual “organizer”; however, each has its own set of consequences realized with regards to the user indicated as being the organizer. Let’s go over those two places that collectively determine who the organizer is.
I: The Recipient Table
The designation of the organizer in a meeting’s recipient PropertyRowSet is what, I believe, actually decides who the organizer is, as it has the greatest amount of influence on the functional implications of having the status of being the organizer.
A PropertyRowSet is a data structure discussed in the [MS-OXCDATA] Exchange server protocol document is simply a structure that has a counted number of PropertyRow structures. Essentially, it is a table where the number of columns in each row is not exactly set in stone (sounds like something right up Microsoft’s alley). When discussing a recipient table, these PropertyRow structures are actually RecipientRow structures, which are also introduced in the [MS-OXCDATA], but expanded upon in [MS-OXOCAL - 184.108.40.206], which begins to go over the actual properties one may encounter in an entry in the recipient table.
By the way, I love how Microsoft introduces the concept of a RecipientRow: “It is rather complex but can be considered as a sequence of three different parts…”
When we step outside of the design and into the more real-world side of things, we’ll find implementations of the recipient table on any type of message, including appointments and meetings. We can retrieve the recipient table by making an IMAPIProp::OpenProperty call, specifying PR_MESSAGE_RECIPIENTS for the property tag and IID_IMAPITable for the interface identifier. You’ll be able to do this more easily by using either OutlookSpy, MFCMapi, which all have options named something similar to “Open Recipients Table”. I’m not sure how easy it is to get to what we want her from the OOM, or even Redemption, but it should be accessible using the appropriate property tags (at least in Redemption’s case…I try to avoid the OOM when doing anything off the beaten path).
Inside the recipient table, we’ll find a RecipientRow for every single attendee to the meeting, including one for the organizer. On each row is one particular property of importance, and that is the PR_RECIPIENT_FLAGS property. You can find information regarding the specifics of this property in the [MS-OXOCAL], however I’ll help you out a bit and plop a picture relevant to what we’re talking about below:
Structure of the PR_RECIPIENT_FLAGS Property
We can see above a number of bit fields we can set. The bit we’re interested in is the second bit, which is known as the recipOrganizer bit. Setting this bit to 1 makes the user associated with the RecipientRow that this property is in the de facto organizer of the appointment. This then implies that only a single RecipientRow can have this bit set. I’m not sure what’ll happen if more than one does have it set, you’ll have to build a custom MAPI client to find out.
So, in other words: the organizer is officially determined to be the user whose has the recipOrganizer bit set in their associated RecipientRow in the appointment’s recipient table. There are other properties in the RecipientRow besides the recipient flags, including one or more that store the recipient’s entry ID. No doubt, then, it is through the user’s RecipientRow that Outlook is able to retrieve the kind of information we were being treated to earlier when hovering our mouse over our name in the Scheduling Assistant.
Unfortunately, this is not the entire story. Despite the designation via the user’s RecipientRow being the official way of becoming the organizer, it may surprise you to know that the Organizer property returned by the OOM (I can’t speak as for Redemption, didn’t test it out), which is the most common means of exposure of the organizer’s identity to the outside via an API (in the case of an Outlook solution, at least) is in no way influenced by the recipOrganizer bit, the PR_RECIPIENT_FLAGS property, or any at all to do with the recipient table!
This leads us to the second place an organizer is “set”.
The value returned by the Organizer property does not originate from the appointment’s recipient table at all. Instead, it actually comes from the PR_SENT_REPRESENTING_NAME property, found on the appointment itself. So, there you go…that’s where the money is.
You’re probably already aware (from being told so somewhere else) that you cannot change the organizer. Consequentially, the Organizer property is read-only. You cannot set the Organizer property. Well, while it is more or less true that you cannot change who the real organizer is, you can have influence on what Organizer returns.
It may surprise you to know that by changing the value of PR_SENT_REPRESENTING_NAME, you will change what the Organizer property returns. Some places in Outlook do use this property to display the organizer’s name, so you will influence those areas. In some places, however, Outlook defers to the display name stored in the recipient table. It does not seem possible to edit a RecipientRow once a message has been saved; at least, I am unable to do so using OutlookSpy and MFCMapi. Perhaps it is still technically possible to with the Redemption library or raw Extended MAPI. I’d be interested to know if anyone has any insight on that.
Here’s some code to demonstrate how to change the Organizer property in Outlook (when we’re in Outlook, we have to get the correct DASL property name):
private void ChangeOrganizer(AppointmentItem appointment)
PropertyAccessor accessor = appointment.PropertyAccessor;
accessor.SetProperty("http://schemas.microsoft.com/mapi/proptag/0x0042001F", "Matt Weber");
// 'appointment.Organizer' will now return "Matt Weber".
And here’s some code to do the same with Redemption, which is a little bit simpler:
private void ChangeOrganizer(RDOAppointmentItem appointment)
appointment.SentOnBehalfOfName = "Matt Weber";
An interesting thing to note is that the PR_SENT_REPRESENTING_NAME property can be found on both appointment and normal mail messages, and thus can be set on either. Regardless, only appointment objects will have an actual “organizer”. Changing the PR_SENT_REPRESENTING_NAME property on an email will change the name of the sender of the email.
Why Relying on the Organizer Property is Dangerous
Seeing how the Organizer (and thus the PR_SENT_REPRESENTING_NAME property) is not actually (guaranteed to be) based on who the real organizer is, relying on it in your program code can be very dangerous. It is really a bad idea, and I’ll provide a very real-world example showing why.
If you cater to customers that belong to the corporate world, you should be aware of and always plan on the possibility of a merger or acquisition involving that customer occurring. Many times, during the process of the merger of acquisition, company-wide changes to the display names of their users will be rolled out via Active Directory. Perhaps the company is now becoming a more “world-wide” company, and thus needs to append the name of a country to all employees’ display names based on the location of their office.
When changes are made to User objects in Active Directory, those changes are going to eventually propagate to Exchange’s Global Address List via a management agent. This means, then, that those changes will be reflected in all address entry objects returned when operating within an Outlook or Exchange environment. Guess what happens to the values returned by properties like PR_SENT_REPRESENTING_NAME and, ultimately, the OOM’s Organizer property? Nothing! They will remain the same; they are not synchronized or hooked up to Active Directory in any way shape or form.
So what will happen then, if you happen to have code responsible for determining if the current user is the organizer of an appointment, which happens to use current Active Directory information for figuring out who the current user is, and the appointment’s Organizer property for figuring out who the organizer is? It won’t work anymore, because they will be completely out of sync.
Therefore, it is very dangerous to rely on, frankly, any string property relating to users exposed by MAPI’s data model.
What’s the alternative here?
The proper way to establish organizer identity is to look past the OOM’s Organizer property and PR_SENT_REPRESENTING_NAME property, and instead use the PR_SENT_REPRESENTING_ENTRYID property (which is exposed by Redemption with the SentOnBehalfOfEntryId property) to retrieve the address entry of the user. This method will survive abrupt, organization-wide changes committed to Active Directory.
The best alternative, however, would be to defer to the recipient table. You would need to go over each RecipientRow until you located the one with the recipOrganizer bit set, and then use the PR_ENTRYID property located in that RecipientRow in order to open up the user’s associated address entry. Note that there is also a PR_RECIPIENT_ENTRYID which may be available and I am not sure as to what the different might be between the two properties; in all instances I’ve observed, both the PR_ENTRYID and PR_RECIPIENT_ENTRYID properties had the same value.