We’ve come a long way since the early days of Schedule+. Much development has been done to refine and smoothen the way calendar meeting requests are handled across the range of Outlook clients and now Teams. However, I still receive more questions about calendars than any other aspect of Teams or Outlook. The requests vary from how to add a disclaimer to meeting requests, or removing items from calendars with PowerShell, to figuring out who receives invitations to Teams meetings. It’s a never-ending procession of queries.
Automatic Processing
A recent question covered the response received for a meeting request sent to a room mailbox. Typically, room mailboxes (which do not need Exchange Online licenses) are used to control bookings of public spaces like conference rooms. Background processes such as the Calendar Attendant review incoming requests against the configuration (policy) defined for the target mailbox and decide if a request is successful and the room can be reserved for the requested time. Users receive email to tell them if their calendar meeting request is successful, denied, or waiting approval by a delegate who controls booking requests.
Traditionally, people waited for the email to come back to say if they have a room for their meeting. OWA and Outlook try to stop users booking rooms which are already reserved. Outlook (Figure 1) uses a MailTip, while OWA takes a more forceful approach and demands confirmation before sending a meeting request (Figure 2).
Figure 1: Outlook desktop’s polite mail tip about an unavailable meeting room
Figure 2: OWA asks for confirmation before sending a meeting request
Either way, the person creating the calendar meeting request can still go ahead and attempt to schedule the room. At that point, the resource booking assistant kicks in to decide if the request is acceptable. The easiest situation is when the requested time slot is available, and the policy assigned to the room mailbox allows automatic acceptance of requests. The Set-CalendarProcessing cmdlet supports a bunch of parameters to allow administrator to tune exactly how incoming meeting requests for a room mailbox are dealt with.
For now, let’s assume that the assistant resolves the policy and decides to accept or reject the request, or that it is tentatively accepted pending review by a delegate. The next step is to send the meeting organizer email to inform them what’s happening.
Sending Corporate Information in Meeting Responses
Which brings me to my point. It’s often overlooked that you can insert some informational text in meeting responses for calendar meeting requests. Look at Figure 3 to see a message about leaving the room clean and tidy after the meeting.
Figure 3: A rejection message because a room is already booked
The text inserted in meeting responses comes from the calendar processing configuration for the mailbox. In this case, I ran the Set-CalendarProcessing cmdlet to set two values. The AddAdditionalResponse switch is $True to force Exchange Online to add the extra text while the AdditionalResponse property holds the text to insert. As shown here, if some basic HTML formatting commands are included, they are used.
Set-CalendarProcessing -Identity "Room 101" -AddAdditionalResponse $True -AdditionalResponse "Please remember to leave the room <b>clean and tidy</b> with all equipment <u>back in its storage</u>. Thank you for using the corporate room scheduling system!"
It’s simple to apply the same text to all room mailboxes by running Get-ExoMailbox to find the mailboxes and then piping the set of room mailbox objects to Set-CalendarProcessing.
Get-ExoMailbox -RecipientTypeDetails RoomMailbox | Set-CalendarProcessing -AddAdditionalResponse $True -AdditionalResponse "Please remember to leave the room <b>clean and tidy</b> with all equipment <u>back in its storage</u>. Thank you for using the corporate room scheduling system!"
Creating Complex Text for Meeting Responses
I haven’t experimented to find the outer limits to discover how much text can be input, but it seems like it is around 1024 characters, meaning that it is feasible to create a nice message. For instance, I used this online editor to create the text of the message shown in Figure 4.
Figure 4: Including helpful hints in the automatic response for a calendar room booking
In this case, the PowerShell command used was:
Set-CalendarProcessing -Identity "Room 101" -AdditionalResponse '<h2>Welcome to the Corporate Room Scheduling System</h2><p>We have a few basic rules for you to follow.</p><ol>
<li>Please keep the room tidy and remove rubbish at the end of your meeting.</li><li>Please do not change the settings of the AV equipment.</li><li>Please clean the whiteboard before you leave.</li><li>Advise Corporate Meetings if you have any problems by sending email to mailto:<a href="mailto:corporatemeetings@office365itpros.com">Corporate Meetings.</a></li></ol><p><strong>Room 101</strong> can hold up to <strong>12</strong> people. Please do not exceed this capacity.</p><p>If you need <strong>catering</strong>, please contact Trina at 147-1497.</p><p>Thanks for meeting with us!<img src="https://html5-editor.net/tinymce/plugins/emoticons/img/smiley-smile.gif" alt="smile" /></p><p> </p>'
The HTML and text are enclosed in single quote marks because some of the HTML commands use double quotes. It wouldn’t take a lot of extra code to read basic text from a file and customize the text (for example, adding some details about the capacity, equipment, or other information) before updating each room mailbox.
Simple Update, Big Impact
Adding some extra text to responses to calendar meeting requests can have a big impact. It’s the kind of simple but useful change that people often don’t know about. Discovering the hidden corners of Microsoft 365 is delightful, at least to me…
We explore all sorts of dark corners of Office 365 apps as we build content for the Office 365 for IT Pros eBook. In this case, the corner proved to be full of sweetness and light!
22 Replies to “How to Customize Responses to Calendar Meeting Requests for Conference Rooms”
HI Tony, thanks for the article and the HTML tips. I was excited to see you mention Outlook shows a MailTip if the Room is already booked (busy) when someone is planning a conflicting meeting. I don’t see this “Rooms are currently unavailable” MailTip on my tenant though, is this something new? Thanks, Ryan.
HI Tony, Thanks for the article, I have a question about the Complex text. is this text only visible when the meeting is accepted or can I also set up in Exchange Online that a text is only visible when the meeting is declined? We want to inform our users about why their appointment has been declined. Thanks, Wouter.
@Tony:
Thank you for this great article. I’m currently deep diving into the creation of rooms, workspaces and all the surrounding capabilities by means of PowerShell.
many thanks for your article. i have a small question. Im trying to add in to the response email the eventid of the created calendar event
eventID , the identifier of the event created in the calendar
any Idea if this is possible ?
thanks a lot
If a Room mailbox is migrated to Office 365, still the auto-response email shall come from Exchange Server 2016? As i noticed it says “Sent by Microsoft Exchange Server 2016”. Can you elaborate?
I see in exchange where you can automatically send a reply to the meeting organizer under Booking Options, but is there a way to send that message to everyone you are inviting to the meeting? My company has the receptionist control meeting events for certain offices and would like everyone to receive the automatic reply for those rooms.
I know this is quite some time after the article was written, but I have a tangential question. I’m trying to get the same sort of experience but for a User mailbox. Using the PowerShell command Set-MailboxAutoReplyConfiguration, and the appropriate Automatic replies settings, it appears that one can set a specific DeclineMeetingMessage, very similar to the AdditionalMessage on the Rooms, like you’ve outlined above. But for the life of me, I can get the automated declining of the meeting request, but the response is always the InternalMessage (or ExternalMessage, depending on sending account). If feels like the DeclineMeetingMessage has never been implemented or it’s been deprecated. Any insight?
Here’s the gist of the command I was hoping would work:
Set-MailboxAutoReplyConfiguration -Identity “UserName” -AutoReplyState Enabled -InternalMessage “Internal auto-reply message.” -ExternalMessage “External auto-reply message.” -ExternalAudience All -AutoDeclineFutureRequestsWhenOOF $True -DeclineMeetingMessage “Message in HTML markup goes here”.
One can even run the following flags “-DeclineAllEventsForScheduledOOF” and “-DeclineEventsForScheduledOOF” to clear out the calendar for the automatic response duration. Everything goes fine EXCEPT for the specific message for DeclineMeetingMessage. The sender gets an response and then the same response in the declined notification.
I greatly appreciate any insight, as well as your time in considering this. I’ll find a different solution for now but am very curious what went wrong.
Loading...
This a great article. It helped me get this setup, but I noticed that the custom text is only added to the automatic “tenative” response. Our rooms have a resource delegate assigned that has to do the actual approve or decline of the room. If the delegate accepts the request our custom text does not show up on that email notification. Do you know if there is away to get that to show up there as well?
I think that when a delegate manually processes a room request, the notification process flows from their action rather than the action of the background calendar assistant. I don’t know (offhand, no testing done) how to get the text to show up there.
I guess that makes sense even if I don’t like it working that way. Thanks for the quick reply.
Loading...
Hi Tony –
I’ve never heard of this being done as nobody has ever asked about this in all my years of administering Exchange/O365 environments. Today someone inquired about this very thing & I was glad to see your post straight off. I’ll be implementing this soon. Good to also know the behavior of this seems to only be with responses directed by the Calendar Assistance and not responses sourced by a Delegate (meeting approver).
Another question to ‘piggy-back’ this post if I may – is there a way to make a Room Calendar a ‘catch-all’ calendar for other Room Calendars; i.e. to make it a ‘hub’ Calendar for a department to look at to see all meetings across other department Calendars instead of staff having to view several Room Calendars individually? The only way I’ve seen is making all Room Calendars ‘subscribable/publishable’, then take the URL from them and add the URLs to this ‘hub’ Calendar. But, I think that would make internal/corporate Calendars publically viewable, correct? Assuming an external user knew the internal Calendars’ URLs. And, if this is even possible, seems to be a lot of work/steps to do what I want. I have done quite a bit of searching & to this point, no success in finding an answer. Thoughts?
Thanks in advance.
I guess you could have a script that searches for new meetings in designated room mailboxes and adds them to the calendar of a central room. Fetching the meeting data isn’t too hard (see https://office365itpros.com/2023/02/10/room-mailboxes-usage-pattern/). Posting the new meetings should be reasonably straightforward using the Graph APIs. And you could have an Azure Automation runbook execute every 15 minutes to check and populate new meetings. I haven’t done this, but it’s one approach to explore.
{"id":null,"mode":"button","open_style":"in_modal","currency_code":"EUR","currency_symbol":"\u20ac","currency_type":"decimal","blank_flag_url":"https:\/\/office365itpros.com\/wp-content\/plugins\/tip-jar-wp\/\/assets\/images\/flags\/blank.gif","flag_sprite_url":"https:\/\/office365itpros.com\/wp-content\/plugins\/tip-jar-wp\/\/assets\/images\/flags\/flags.png","default_amount":100,"top_media_type":"featured_image","featured_image_url":"https:\/\/office365itpros.com\/wp-content\/uploads\/2022\/11\/cover-141x200.jpg","featured_embed":"","header_media":null,"file_download_attachment_data":null,"recurring_options_enabled":true,"recurring_options":{"never":{"selected":true,"after_output":"One time only"},"weekly":{"selected":false,"after_output":"Every week"},"monthly":{"selected":false,"after_output":"Every month"},"yearly":{"selected":false,"after_output":"Every year"}},"strings":{"current_user_email":"","current_user_name":"","link_text":"Virtual Tip Jar","complete_payment_button_error_text":"Check info and try again","payment_verb":"Pay","payment_request_label":"Office 365 for IT Pros","form_has_an_error":"Please check and fix the errors above","general_server_error":"Something isn't working right at the moment. Please try again.","form_title":"Office 365 for IT Pros","form_subtitle":null,"currency_search_text":"Country or Currency here","other_payment_option":"Other payment option","manage_payments_button_text":"Manage your payments","thank_you_message":"Thank you for supporting the work of Office 365 for IT Pros!","payment_confirmation_title":"Office 365 for IT Pros","receipt_title":"Your Receipt","print_receipt":"Print Receipt","email_receipt":"Email Receipt","email_receipt_sending":"Sending receipt...","email_receipt_success":"Email receipt successfully sent","email_receipt_failed":"Email receipt failed to send. Please try again.","receipt_payee":"Paid to","receipt_statement_descriptor":"This will show up on your statement as","receipt_date":"Date","receipt_transaction_id":"Transaction ID","receipt_transaction_amount":"Amount","refund_payer":"Refund from","login":"Log in to manage your payments","manage_payments":"Manage Payments","transactions_title":"Your Transactions","transaction_title":"Transaction Receipt","transaction_period":"Plan Period","arrangements_title":"Your Plans","arrangement_title":"Manage Plan","arrangement_details":"Plan Details","arrangement_id_title":"Plan ID","arrangement_payment_method_title":"Payment Method","arrangement_amount_title":"Plan Amount","arrangement_renewal_title":"Next renewal date","arrangement_action_cancel":"Cancel Plan","arrangement_action_cant_cancel":"Cancelling is currently not available.","arrangement_action_cancel_double":"Are you sure you'd like to cancel?","arrangement_cancelling":"Cancelling Plan...","arrangement_cancelled":"Plan Cancelled","arrangement_failed_to_cancel":"Failed to cancel plan","back_to_plans":"\u2190 Back to Plans","update_payment_method_verb":"Update","sca_auth_description":"Your have a pending renewal payment which requires authorization.","sca_auth_verb":"Authorize renewal payment","sca_authing_verb":"Authorizing payment","sca_authed_verb":"Payment successfully authorized!","sca_auth_failed":"Unable to authorize! Please try again.","login_button_text":"Log in","login_form_has_an_error":"Please check and fix the errors above","uppercase_search":"Search","lowercase_search":"search","uppercase_page":"Page","lowercase_page":"page","uppercase_items":"Items","lowercase_items":"items","uppercase_per":"Per","lowercase_per":"per","uppercase_of":"Of","lowercase_of":"of","back":"Back to plans","zip_code_placeholder":"Zip\/Postal Code","download_file_button_text":"Download File","input_field_instructions":{"tip_amount":{"placeholder_text":"How much would you like to tip?","initial":{"instruction_type":"normal","instruction_message":"How much would you like to tip? Choose any currency."},"empty":{"instruction_type":"error","instruction_message":"How much would you like to tip? Choose any currency."},"invalid_curency":{"instruction_type":"error","instruction_message":"Please choose a valid currency."}},"recurring":{"placeholder_text":"Recurring","initial":{"instruction_type":"normal","instruction_message":"How often would you like to give this?"},"success":{"instruction_type":"success","instruction_message":"How often would you like to give this?"},"empty":{"instruction_type":"error","instruction_message":"How often would you like to give this?"}},"name":{"placeholder_text":"Name on Credit Card","initial":{"instruction_type":"normal","instruction_message":"Enter the name on your card."},"success":{"instruction_type":"success","instruction_message":"Enter the name on your card."},"empty":{"instruction_type":"error","instruction_message":"Please enter the name on your card."}},"privacy_policy":{"terms_title":"Terms and conditions","terms_body":null,"terms_show_text":"View Terms","terms_hide_text":"Hide Terms","initial":{"instruction_type":"normal","instruction_message":"I agree to the terms."},"unchecked":{"instruction_type":"error","instruction_message":"Please agree to the terms."},"checked":{"instruction_type":"success","instruction_message":"I agree to the terms."}},"email":{"placeholder_text":"Your email address","initial":{"instruction_type":"normal","instruction_message":"Enter your email address"},"success":{"instruction_type":"success","instruction_message":"Enter your email address"},"blank":{"instruction_type":"error","instruction_message":"Enter your email address"},"not_an_email_address":{"instruction_type":"error","instruction_message":"Make sure you have entered a valid email address"}},"note_with_tip":{"placeholder_text":"Your note here...","initial":{"instruction_type":"normal","instruction_message":"Attach a note to your tip (optional)"},"empty":{"instruction_type":"normal","instruction_message":"Attach a note to your tip (optional)"},"not_empty_initial":{"instruction_type":"normal","instruction_message":"Attach a note to your tip (optional)"},"saving":{"instruction_type":"normal","instruction_message":"Saving note..."},"success":{"instruction_type":"success","instruction_message":"Note successfully saved!"},"error":{"instruction_type":"error","instruction_message":"Unable to save note note at this time. Please try again."}},"email_for_login_code":{"placeholder_text":"Your email address","initial":{"instruction_type":"normal","instruction_message":"Enter your email to log in."},"success":{"instruction_type":"success","instruction_message":"Enter your email to log in."},"blank":{"instruction_type":"error","instruction_message":"Enter your email to log in."},"empty":{"instruction_type":"error","instruction_message":"Enter your email to log in."}},"login_code":{"initial":{"instruction_type":"normal","instruction_message":"Check your email and enter the login code."},"success":{"instruction_type":"success","instruction_message":"Check your email and enter the login code."},"blank":{"instruction_type":"error","instruction_message":"Check your email and enter the login code."},"empty":{"instruction_type":"error","instruction_message":"Check your email and enter the login code."}},"stripe_all_in_one":{"initial":{"instruction_type":"normal","instruction_message":"Enter your credit card details here."},"empty":{"instruction_type":"error","instruction_message":"Enter your credit card details here."},"success":{"instruction_type":"normal","instruction_message":"Enter your credit card details here."},"invalid_number":{"instruction_type":"error","instruction_message":"The card number is not a valid credit card number."},"invalid_expiry_month":{"instruction_type":"error","instruction_message":"The card's expiration month is invalid."},"invalid_expiry_year":{"instruction_type":"error","instruction_message":"The card's expiration year is invalid."},"invalid_cvc":{"instruction_type":"error","instruction_message":"The card's security code is invalid."},"incorrect_number":{"instruction_type":"error","instruction_message":"The card number is incorrect."},"incomplete_number":{"instruction_type":"error","instruction_message":"The card number is incomplete."},"incomplete_cvc":{"instruction_type":"error","instruction_message":"The card's security code is incomplete."},"incomplete_expiry":{"instruction_type":"error","instruction_message":"The card's expiration date is incomplete."},"incomplete_zip":{"instruction_type":"error","instruction_message":"The card's zip code is incomplete."},"expired_card":{"instruction_type":"error","instruction_message":"The card has expired."},"incorrect_cvc":{"instruction_type":"error","instruction_message":"The card's security code is incorrect."},"incorrect_zip":{"instruction_type":"error","instruction_message":"The card's zip code failed validation."},"invalid_expiry_year_past":{"instruction_type":"error","instruction_message":"The card's expiration year is in the past"},"card_declined":{"instruction_type":"error","instruction_message":"The card was declined."},"missing":{"instruction_type":"error","instruction_message":"There is no card on a customer that is being charged."},"processing_error":{"instruction_type":"error","instruction_message":"An error occurred while processing the card."},"invalid_request_error":{"instruction_type":"error","instruction_message":"Unable to process this payment, please try again or use alternative method."},"invalid_sofort_country":{"instruction_type":"error","instruction_message":"The billing country is not accepted by SOFORT. Please try another country."}}}},"fetched_oembed_html":false}
HI Tony, thanks for the article and the HTML tips. I was excited to see you mention Outlook shows a MailTip if the Room is already booked (busy) when someone is planning a conflicting meeting. I don’t see this “Rooms are currently unavailable” MailTip on my tenant though, is this something new? Thanks, Ryan.
Could be. Things change pretty quickly inside Office 365…
HI Tony, Thanks for the article, I have a question about the Complex text. is this text only visible when the meeting is accepted or can I also set up in Exchange Online that a text is only visible when the meeting is declined? We want to inform our users about why their appointment has been declined. Thanks, Wouter.
I don’t believe so. I don’t think the calendar agent differentiates like that.
@Tony:
Thank you for this great article. I’m currently deep diving into the creation of rooms, workspaces and all the surrounding capabilities by means of PowerShell.
Is there way to parse the -identity element like this
$TargetUsers = Import-CSV “.\ROOMS-TEST.csv”
$upn = [System.Collections.Generic.List[Object]]::new()
ForEach ($U in $TargetUsers) { $upn.Add($U.UserPrincipalName) }
Set-CalendarProcessing -Identity $upn -AddAdditionalResponse $True -AdditionalResponse ‘Thank you for booking.’
I’m sorry. I don’t understand what you’re trying to do. Can you explain further?
many thanks for your article. i have a small question. Im trying to add in to the response email the eventid of the created calendar event
eventID , the identifier of the event created in the calendar
any Idea if this is possible ?
thanks a lot
No idea. I haven’t tried.
Hi Tony,
If a Room mailbox is migrated to Office 365, still the auto-response email shall come from Exchange Server 2016? As i noticed it says “Sent by Microsoft Exchange Server 2016”. Can you elaborate?
IT’s just a string that the developers have failed to update. Nothing much to worry about.
I see in exchange where you can automatically send a reply to the meeting organizer under Booking Options, but is there a way to send that message to everyone you are inviting to the meeting? My company has the receptionist control meeting events for certain offices and would like everyone to receive the automatic reply for those rooms.
You’ll have to include the receptionist’s name in the email recipient list for them to receive a copy. Or have them schedule the meetings.
I know this is quite some time after the article was written, but I have a tangential question. I’m trying to get the same sort of experience but for a User mailbox. Using the PowerShell command Set-MailboxAutoReplyConfiguration, and the appropriate Automatic replies settings, it appears that one can set a specific DeclineMeetingMessage, very similar to the AdditionalMessage on the Rooms, like you’ve outlined above. But for the life of me, I can get the automated declining of the meeting request, but the response is always the InternalMessage (or ExternalMessage, depending on sending account). If feels like the DeclineMeetingMessage has never been implemented or it’s been deprecated. Any insight?
I never looked at doing this for a user mailbox. When I get some time, I will have a poke around to see if I can figure out what’s going on.
Here’s the gist of the command I was hoping would work:
Set-MailboxAutoReplyConfiguration -Identity “UserName” -AutoReplyState Enabled -InternalMessage “Internal auto-reply message.” -ExternalMessage “External auto-reply message.” -ExternalAudience All -AutoDeclineFutureRequestsWhenOOF $True -DeclineMeetingMessage “Message in HTML markup goes here”.
One can even run the following flags “-DeclineAllEventsForScheduledOOF” and “-DeclineEventsForScheduledOOF” to clear out the calendar for the automatic response duration. Everything goes fine EXCEPT for the specific message for DeclineMeetingMessage. The sender gets an response and then the same response in the declined notification.
I greatly appreciate any insight, as well as your time in considering this. I’ll find a different solution for now but am very curious what went wrong.
This a great article. It helped me get this setup, but I noticed that the custom text is only added to the automatic “tenative” response. Our rooms have a resource delegate assigned that has to do the actual approve or decline of the room. If the delegate accepts the request our custom text does not show up on that email notification. Do you know if there is away to get that to show up there as well?
I think that when a delegate manually processes a room request, the notification process flows from their action rather than the action of the background calendar assistant. I don’t know (offhand, no testing done) how to get the text to show up there.
I guess that makes sense even if I don’t like it working that way. Thanks for the quick reply.
Hi Tony –
I’ve never heard of this being done as nobody has ever asked about this in all my years of administering Exchange/O365 environments. Today someone inquired about this very thing & I was glad to see your post straight off. I’ll be implementing this soon. Good to also know the behavior of this seems to only be with responses directed by the Calendar Assistance and not responses sourced by a Delegate (meeting approver).
Another question to ‘piggy-back’ this post if I may – is there a way to make a Room Calendar a ‘catch-all’ calendar for other Room Calendars; i.e. to make it a ‘hub’ Calendar for a department to look at to see all meetings across other department Calendars instead of staff having to view several Room Calendars individually? The only way I’ve seen is making all Room Calendars ‘subscribable/publishable’, then take the URL from them and add the URLs to this ‘hub’ Calendar. But, I think that would make internal/corporate Calendars publically viewable, correct? Assuming an external user knew the internal Calendars’ URLs. And, if this is even possible, seems to be a lot of work/steps to do what I want. I have done quite a bit of searching & to this point, no success in finding an answer. Thoughts?
Thanks in advance.
I guess you could have a script that searches for new meetings in designated room mailboxes and adds them to the calendar of a central room. Fetching the meeting data isn’t too hard (see https://office365itpros.com/2023/02/10/room-mailboxes-usage-pattern/). Posting the new meetings should be reasonably straightforward using the Graph APIs. And you could have an Azure Automation runbook execute every 15 minutes to check and populate new meetings. I haven’t done this, but it’s one approach to explore.
Thank you for the response Tony.