How To: Customize the context ribbon of Outlook 2013 inline response
After Microsoft published the Preview version of Office 2013 we started to receive lots of questions regarding built-in ribbon control IDs. Developers wanted to support the new Microsoft Office version but couldn’t find the required information on MSDN.
At the moment of writing, Microsoft is yet to publish the list of new control identifiers for Office 2013 (see for Office 2007 and Office 2010). And developers continue to express concerns on MSDN (Still no new Schema File for Office 2013) and our forum (How to customize Inline Response Message Ribbon).
So, in my today’s article I would like to draw your attention to the new Inline Response feature introduced in Outlook 2013 and explain how you can add your own controls to its context tabs.
On the right side of the Outlook window you can see the reading pane which has the Reply, Reply All and Forward buttons at the top:
When you click any of these buttons you will see the following changes (for example, I clicked the Reply button in my tests):
The reading pane is transformed to the editable state allowing users to reply to e-mails inline rather than opening a new Inspector window. This feature of Outlook 2013 is called inline response.
How to add custom ribbon controls to Outlook 2013 inline response context
As a developer, you might have noticed the new context tab – MESSAGE – that appears at the top of the Outlook window when the inline response feature is active. How can we add our custom controls to this contextual tab? To demonstrate this, I have developed a sample add-in for Outlook 2013, which adds a ribbon group to the Message tab, see Our context group in the screenshot:
The solution is very simple indeed – you need to use the Context.TabComposeTools value for the Context property and the TabMessage value for the IdMso property of the ADXRibbonTab component! As you probably guessed already I used Add-in Express for Office and .net.
The plug-in also adds a separate contextual tab to the Compose tools context:
In that case you just need to set the Outlook.TabComposeTools value to the Context property of your ADXRibbonTab component.
How to get an inline response item in Outlook 2013
For handling inline replies Outlook 2013 introduces a new event which notifies developers when the inline response is activated – the InlineResponse event. I have also found the InlineResponseClose event on MSDN. It looks like it should be added to Outlook 2013 later ;-) To leverage the extended capabilities from the Word Object Model, developers can use the ActiveInlineResponseWordEditor property, which returns a Word Document of the active inline response.
Also, Outlook 2013 introduces a new property for the Explorer class – ActiveInlineResponse. It allows getting an item which is listed in the Outlook 2013 reading pane in case the inline response is active. Please remember, if you develop an add-in which supports earlier Outlook versions as well using version neutral interops, you need to use the late binding technology to access the ActiveInlineResponse property. The DisplayInlineResponseSubject method used in this sample add-in accepts an instance of the Outlook Application class and displays a message box with the subject of the inline response item.
- C# code example:
private void DisplayInlineResponseSubject(Outlook._Application OutlookApp) { Outlook.Explorer explorer = null; Outlook.MailItem response = null; try { explorer = OutlookApp.ActiveExplorer(); // response = explorer.ActiveInlineResponse; response = explorer.GetType().InvokeMember("ActiveInlineResponse", System.Reflection.BindingFlags.GetProperty | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.Public, null, explorer, null) as Outlook.MailItem; if (response != null) System.Windows.Forms.MessageBox.Show(response.Subject, "The inline response e-mail's subject"); } catch (Exception ex) { System.Windows.Forms.MessageBox.Show(ex.Message, "An exception was thrown in the code..."); } finally { if (response != null) Marshal.ReleaseComObject(response); if (explorer != null) Marshal.ReleaseComObject(explorer); } }
- VB.NET code example:
Private Sub DisplayInlineResponseSubject(OutlookApp As Outlook._Application) Dim explorer As Outlook.Explorer = Nothing Dim response As Outlook.MailItem = Nothing Try explorer = OutlookApp.ActiveExplorer() ' response = explorer.ActiveInlineResponse response = explorer.GetType().InvokeMember("ActiveInlineResponse", _ System.Reflection.BindingFlags.GetProperty Or _ System.Reflection.BindingFlags.Instance Or _ System.Reflection.BindingFlags.Public, _ Nothing, explorer, Nothing) If Not IsNothing(response) Then System.Windows.Forms.MessageBox.Show(response.Subject, _ "The inline response e-mail's subject") End If Catch ex As Exception System.Windows.Forms.MessageBox.Show(ex.Message, _ "An exception was thrown in the code...") Finally If Not IsNothing(response) Then Marshal.ReleaseComObject(response) If Not IsNothing(explorer) Then Marshal.ReleaseComObject(explorer) End Try End Sub
See you next week and have a great weekend! :-)
Available downloads:
These sample Outlook 2013 add-ins were developed using Add-in Express for Office and .net:
C# Outlook addin
VB.NET Outlook addin
15 Comments
Thank you for this useful article! My aim is to add a BCC by using a similar code.
However, I found out that ‘response’ does not have a “BCC” property. How do I get to this property?..
Hi Dmitry,
You can try to use the Item parameter of the InlineResponse event. Type cast it to MailItem and use its properties and methods.
Great How To!
Is it possible to have the example for “Add-in Express for VCL”
I’m trying to find the equivalence of “explorer.GetType().InvokeMember(“ActiveInlineResponse” in delphi/pascal.
Thanks!
Hi Joey,
You can use late binding in Delphi by casting an interface variable to the OleVariant type:
var
IResponse: IDispatch;
begin
// …
IResponse := OleVariant(explorer).ActiveInlineResponse;
// …
Just for information, it seems Microsoft finally published the list of buttons identifier: https://www.microsoft.com/en-us/download/details.aspx?id=36798
Thank you, Fabrice!
Hi,
any ideas why this “The solution is very simple indeed – you need to use the Context.TabComposeTools value for the Context property and the TabMessage value for the IdMso property of the ADXRibbonTab component!” does NOT work? Neither Group nor button is added after changing the values of These two properties of a newly created empty ADXRibbonTab.
Would be thankful for any advice, because I do feel that this could turn out not to be “very simple”.
Thanks in advance
Katharina
Hello Katharina,
You can use the links at the end of the text to download a sample project. Find the InitializeComponent() method of the add-in module and compare the settings with your project. This method is generated to reflect the components and their settings that you use in the add-in module designer. Hope this helps.
Hello Katharina,
Please use the following Ribbon XML markup for VSTO based add-ins:
<customUI xmlns=”https://schemas.microsoft.com/office/2006/01/customui” onLoad=”RibbonLoaded” loadImage=”LoadImages”>
<ribbon startFromScratch=”false”>
<contextualTabs>
<tabSet idMso=”TabComposeTools”>
<tab getVisible=”getVisible” idMso=”TabMessage”>
<group getLabel=”getLabel” getVisible=”getVisible” id=”MYRibbonGroup”>
<button getDescription=”getDescription” getEnabled=”getEnabled” getImage=”getImage” getLabel=”getLabel” getShowImage=”getShowImage” getShowLabel=”getShowLabel” getSize=”getSize” getVisible=”getVisible” id=”MyRibbonButton” onAction=”onAction” />
</group>
</tab>
</tabSet>
</contextualTabs>
</ribbon>
</customUI>
Don’t forget to add the required callback to your code behind files.
I give up.
And curse at those who made it THAT much more difficult to add a button to a contextual ribbon than to an ordinary ribbon. Have to accept it, but cannot understand. Thanks for your attempts.
Katharina,
I am really sorry that you have had continued difficulties with this.
Please send your project to our support email address, I will try to find the cause of the problem and fix it. You can find our support email address in the readme.txt file located in the Add-in Express installation folder.
I’m trying to create a ribbon button in the inline response scenario where it will cause the email to be sent after modifying the subject. Is there any way to trigger the send event in this situation???
Hi Rob,
You can use the Send method of the Outlook.MailItem object to send an email.
I’m having the same challenge as Rob: unable to send inline mail. Even after casting the ActiveInlineResponse to a MailItem object the Send method still fails.
@Dmitry: according to MSDN (url below) the “Send()” method is unavailable… which is very confusing for me…
https://msdn.microsoft.com/en-us/library/office/jj231535.aspx
Hi Bob,
To avoid this limitation you can save the email item, store its EntryID property, close the Inline Response (by selecting another email), find the unsent email by using EntryID and send it. Please see the code sample below:
private string _entryID = string.Empty;
private Timer _timer = null;
private void AddinModule_AddinInitialize(object sender, EventArgs e)
{
this._timer = new Timer();
this._timer.Enabled = false;
this._timer.Interval = 500;
this._timer.Tick += DoTimerTick;
}
private void adxRibbonButton1_OnClick(object sender, IRibbonControl control, bool pressed)
{
Outlook._Explorer explorer = OutlookApp.ActiveExplorer();
if (explorer != null)
try
{
object objResponse = explorer.ActiveInlineResponse;
if (objResponse != null)
try
{
Outlook._MailItem mail = objResponse as Outlook._MailItem;
if (mail != null)
{
// TODO check properties (To, CC, BCC, Subject)
mail.Save();
_entryID = mail.EntryID;
explorer.ClearSelection(); // and close Inline Response
}
}
finally { Marshal.ReleaseComObject(objResponse); }
}
finally { Marshal.ReleaseComObject(explorer); }
}
private void adxOutlookEvents_ExplorerInlineResponseCloseEx(object sender, object sourceObject)
{
if (!string.IsNullOrEmpty(this._entryID))
this._timer.Enabled = true;
}
private void DoTimerTick(object sender, EventArgs e)
{
this._timer.Enabled = false;
try
{
Outlook._NameSpace ns = OutlookApp.GetNamespace(“MAPI”);
if (ns != null)
try
{
Outlook._MailItem mailToSend = ns.GetItemFromID(this._entryID, Type.Missing) as Outlook._MailItem;
if (mailToSend != null)
try
{
mailToSend.Send();
}
finally { Marshal.ReleaseComObject(mailToSend); }
}
finally { Marshal.ReleaseComObject(ns); }
}
finally { this._entryID = string.Empty; }
}