Unable to set MAPI Header on draft mail when it is a reply

Add-in Express™ Support Service
That's what is more important than anything else

Unable to set MAPI Header on draft mail when it is a reply
 
Andrei Smolin


Add-in Express team


Posts: 14094
Joined: 2006-05-11
Hello Niels,

I set a custom property on the AppointmentItem, and then on the MeetingItem. On the receiving end, I see my property on the MeetingItem only. Note that in Sent Items folder, both MeetingItem and AppointmentItem have this property.

Regards from Belarus (GMT+3),

Andrei Smolin
Add-in Express Team Leader
Posted 17 Jul, 2017 06:48:46 Top
Niels Ziegler




Posts: 49
Joined: 2017-02-03
By now I have to believe it get's lost somewhere during transport. The header is lost when the recipient is inside the organisation, even if it is located on the same exchange database. According to the routing information in the header, the server still passes the item to another server. I have asked exchange specalists to help identify the problem because I don't think that I can do more on the client side.
Posted 18 Jul, 2017 09:06:49 Top
Andrei Smolin


Add-in Express team


Posts: 14094
Joined: 2006-05-11
Hello Niels,

Also check if this is produced by the antivirus software product they use.

Regards from Belarus (GMT+3),

Andrei Smolin
Add-in Express Team Leader
Posted 18 Jul, 2017 10:00:54 Top
Niels Ziegler




Posts: 49
Joined: 2017-02-03
Are you sending those meetings on an exchange environment?

I now have two exchange environments where I see all custom x-headers removed for meetings. One is a test environment with no antivirus or other third party tools. This is all internal transport, not through some gateway.
Posted 18 Jul, 2017 12:29:34 Top
Niels Ziegler




Posts: 49
Joined: 2017-02-03
I wanted to try what you said, so I set the header again during sendItem, explicitly on the meeting item. Suddenly I see my custom attribute in the Header area, but my previous access methods for mails can not extract it.

Maybe I have to parse the internet-headers attribute, but this is another strange behaviour, only seen on meetingitems.
Posted 18 Jul, 2017 13:06:47 Top
Andrei Smolin


Add-in Express team


Posts: 14094
Joined: 2006-05-11
Hello Niels,

We use Exchange online.

I've just re-tested retrieving my custom property on the receiving side: this works.

I use this VBA code:

SET:
Private Sub Application_ItemSend(ByVal Item As Object, Cancel As Boolean)
    If TypeOf Item Is Outlook.MeetingItem Then
        Dim mt As Outlook.MeetingItem
        Set mt = Item
        mt.PropertyAccessor.SetProperty "http://schemas.microsoft.com/mapi/string/{00020386-0000-0000-C000-000000000046}/X-MyVal", "789"
    End If
End Sub


GET:
Public Sub InspectorJob()
Dim anItem As Outlook.MeetingItem
Set anItem = Application.ActiveInspector().CurrentItem
Dim s As String
 s = anItem.PropertyAccessor.GetProperty("http://schemas.microsoft.com/mapi/string/{00020386-0000-0000-C000-000000000046}/X-MyVal")
Debug.Print s
End Sub


Regards from Belarus (GMT+3),

Andrei Smolin
Add-in Express Team Leader
Posted 19 Jul, 2017 04:36:25 Top
Niels Ziegler




Posts: 49
Joined: 2017-02-03
I am now setting my attribute a second time during the send event, if it's a meeting item. Previously, I would have set it only during editing the appointment, not like you during sending. That is probably the reason it would not be contained in the received meetingItem. Now I can read it when I display the meeting from the inbox.


Here is the next hurdle: When someone replies to that meeting invitation, once again I can not find that attribute. I have tried looking for the "parent" item, then read it from there, but I am failing to find it using the subject. I tried using the "findParent" method as described herehere.
How would you recommend I can find the original item?
Posted 20 Jul, 2017 07:42:21 Top
Andrei Smolin


Add-in Express team


Posts: 14094
Joined: 2006-05-11
Hello Niels,

When you select or open the meeting request that has your custom property, you need to retrieve the property value; further below this value is referred to as VALUE. Note that you may need to modify VALUE so that it answers your business logic. Also, I use PROPERTY to refer to the property to which you assign VALUE.

The further options are these:
- the user can choose Accept/Decline/Tentative without sending a response; I suppose you need not do anything in this case
- the user can choose Accept/Decline/Tentative with "Send the Response Now"; in this case, you need to intercept ItemSend and assign VALUE to PROPERTY of the MeetingItem being sent
- the user can choose Accept/Decline/Tentative with "Edit the Response before Sending"; in this case, you need to intercept the next InspectorActivate and assign VALUE to PROPERTY of the MeetingItem being opened
- the user can choose "Tentative and Propose New Time" or "Decline and Propose New Time"; in this case, you need to intercept the next InspectorActivate and assign VALUE to PROPERTY of the MeetingItem being opened; if the user cancels the Propose New Time dialog, you should get ExplorerActivate
- the user can choose Reply/Reply All/Forward; in this case, you need to intercept the next InspectorActivate and assign VALUE to PROPERTY of the *MailItem* (not MeetingItem) being opened

To handle the scenarios above, you need to intercept the Ribbon commands with these IdMso's:
AcceptInvitationEditResponse
AcceptInvitationSendResponse
AcceptInvitationNoResponse
TentativeInvitationEditResponse
TentativeInvitationSendResponse
TentativeInvitationNoResponse
DeclineInvitationEditResponse
DeclineInvitationSendResponse
DeclineInvitationNoResponse
TentativeProposeNewTime
DeclineAndProposeNewTime
Reply
ReplyAll
Forward

The user options (Ribbon commands) above are available in the meeting inspector and in the explorer; set the Ribbons property of the corresponding Ribbon commands to OutlookMeetingRequestRead and OutlookExplorer.

Regards from Belarus (GMT+3),

Andrei Smolin
Add-in Express Team Leader
Posted 20 Jul, 2017 09:42:28 Top
Niels Ziegler




Posts: 49
Joined: 2017-02-03
Thank you for the extensive list.

So storing the value until the next fitting event comes by is the only option to connect the parent and the new meeting item? Outlook sure is strange. I will try this tomorrow.
Posted 20 Jul, 2017 14:34:04 Top
Andrei Smolin


Add-in Express team


Posts: 14094
Joined: 2006-05-11
Hello Niels,

There's a better approach: you intercept the commands above, cancel them, and pass a unique message - an integer >1024 - to ADXAddinModule.SendMessage(). When the message is received, you get the ADXAddinModule.OnSendMessage event. In the event handler, you filter out the message, set a boolean flag, and invoke the same command programmatically using CommandBars.ExecuteMso(). In the ADXRibbonCommand.OnAction event you pass this call to the Outlook object model. This creates an inspector window or inline response, in the corresponding event handler you check if the event is raised by you or by the user and set (or don't set) the property.

using Outlook = Microsoft.Office.Interop.Outlook;
using Office = Microsoft.Office.Core;
...
private const int WM_USER = 0x0400; // 1024
private const int ReplyInitiatedByUserMessage = WM_USER + 1000;
private const int ReplyInitiatedByUsMessage = WM_USER + 1001;

bool isReplyInitiatedByUser = true;

private void AddinModule_AddinInitialize(object sender, EventArgs e) {
    isReplyInitiatedByUser = true;
}

// the corresponding ADXRibbonCommand has IdMso set to "Reply"
private void adxRibbonCommand1_OnAction(object sender, IRibbonControl control, bool pressed, ADXCancelEventArgs e) {
            
    // cancel user-initiated replies; do nothing otherwise 

    if (isReplyInitiatedByUser) {                
        e.Cancel = true;
        this.SendMessage(ReplyInitiatedByUserMessage);
    } else {
        // do nothing                 
    }
}
private void AddinModule_OnSendMessage(object sender, ADXSendMessageEventArgs e) {
    if (e.Message == ReplyInitiatedByUserMessage) {

        // initialize
        Outlook.Explorer exlporer = this.OutlookApp.ActiveExplorer();
        Office.CommandBars commandBars = exlporer.CommandBars;

        // invoke the Reply command here
        {
            isReplyInitiatedByUser = false;
            commandBars.ExecuteMso("Reply");  
            isReplyInitiatedByUser = true;
        }

        // clean up
        Marshal.ReleaseComObject(commandBars); commandBars = null;
        Marshal.ReleaseComObject(exlporer); exlporer = null;
    }
}
private void adxOutlookAppEvents1_InspectorActivate(object sender, object inspector, string folderName) {
    if (isReplyInitiatedByUser) {
        System.Diagnostics.Debug.WriteLine("!!! user");
    } else {
        System.Diagnostics.Debug.WriteLine("!!! us");
        // check whether the property is set; if not, set it here; 
    }
}


Regards from Belarus (GMT+3),

Andrei Smolin
Add-in Express Team Leader
Posted 21 Jul, 2017 04:38:18 Top