C# Outlook AddIn - Determine EWS Item ID for the selected Email - c#

Is it possible to determine the Exchange Server ItemID for a MailItem (the selected Item in the active explorer)? The solution I am working on has an Outlook AddIn component and another component that accesses mail items through EWS.
I have code similar to the below in my Outlook addin:
Outlook.Explorer ActiveExplorer = Globals.ThisAddIn.Application.ActiveExplorer();
object selectedItem = ActiveExplorer.Selection[1];
Outlook.MailItem selectedEmail = selectedItem as Outlook.MailItem;
In this way I can access certain properties of the email but it is important to the workings of the overall solution that the property values are exactly the same as those returned by EWS. For example, if the property returned a time, it would be important that the time matched down to the millisecond.
If I had the ItemID I could bind to and work with the Item (from within the addin) using something like the below.
Item myItem = Item.Bind(MyExchangeService, MyItemID);
On a whim I have tried binding to MailItem.EntryID but I got a malformed ID error (which didn't surprise me). I have been trying to determine if the Exchange ID was available through MailItem.PropertyAccessor.GetProperty but I am not really familiar with accessing properties in this way and haven't had any luck so far.
Thoughts?

I came across the following Stack Overflow post which didn't exactly answer my question but changed my focus to converting the EntryID into the EWS ID rather than finding the EWS ID.
Exchange ItemID differs from GlobalAppointmentID for Outlook AddIn
With this new angle I was able to find the following site which directly addressed my issue.
https://bernhardelbl.wordpress.com/2013/04/15/converting-entryid-to-ewsid-using-exchange-web-services-ews/
I have posted the code here in full in case the link gets broken.
string ConvertHexEntryIdToEwsId(ExchangeService esb, string sID, string strSMTPAdd)
{
AlternateId objAltID = new AlternateId();
objAltID.Format = IdFormat.HexEntryId;
objAltID.Mailbox = strSMTPAdd;
objAltID.UniqueId = sID;
AlternateIdBase objAltIDBase = esb.ConvertId(objAltID, IdFormat.EwsId);
AlternateId objAltIDResp = (AlternateId)objAltIDBase;
return objAltIDResp.UniqueId;
}

Related

C# Attach to open outlook email, edit and send

I am trying get some C# to attach to an open reply-email (triggered manually by user), on the already running instance of Outlook (opened manually by user). The code should identify the open reply email, edit the subject line and body of the email and send the email.
The problem is that I get as far as identifying the running instance of Outlook and assigning it to an object using one of the Marshal methodsoutApp = Marshal.GetActiveObject("Outlook.Application") as Application, but then I cannot cast it to a MailItem type in order to manipulate its elements e.g. the subject line, body, etc...something like MailItem mailItem = (MailItem)outApp.CreateItem((OlItemType.olMailItem)); throws an invalid cast exception at runtime.
Apologies if I am wrong, but could not find a single example close to this exact sequence of events, one of the closer ones is this post c# outlook open existing instance and reply to email
but then it goes a whole different way. There are tons of posts on how to use the Microsoft.Office.Interop.Outlook to OPEN and then use an instance of Outlook, but hardly anything (that I could find) on how to use an open instance. Any help is appreciated, thank you.
EDIT 08102019:
The code is used from an RPA platform, so there is no risk of it being picked up as malware. The "user" is just a virtual user on an account with purpose-made permissions and a controlled environment...sorry, nothing dark here :-). Anyway, here is the code I am using at the moment which creates a new instance and saves it to drafts in Outlook. It is not what I set out to do, as I explained above, this is just a temporary fix:
OutlookApp outlookApp = new OutlookApp();
MailItem mailItem = (MailItem)outlookApp.CreateItem(OlItemType.olMailItem);
mailItem.To = "test#test.com";
mailItem.Subject = "Test Email Generation";
mailItem.HTMLBody = "<html><body>This is the body of the email.</strong>.<br/> This is another line in the body of the email.</body></html>";
mailItem.Display(false);
System.Threading.Thread.Sleep(3000);
mailItem.Close(OlInspectorClose.olSave);
Marshal.ReleaseComObject(outlookApp);
To get the opened mail item in the inspector window you need:
Use the ActiveInspector method to get an instance of the Inspector class.
The Inspector.CurrentItem property returns an Object representing the current item being displayed in the inspector.
Set any properties like Subject, Body, Recipients and etc.
To get the inline response in the Explorer window you need to use the Explorer.ActiveInlineResponse property which returns an item object representing the active inline response item in the explorer reading pane.

How to get the SMTP Adress of the sender outlook / Exchange

I am trying to get the SMTP Adress of the sender in an outlook plugin.
This worked as expected when I follow the examples from MSDN
like this one here:
private void GetSMTPAddressForRecipients(Outlook.MailItem mail)
{
const string PR_SMTP_ADDRESS =
"http://schemas.microsoft.com/mapi/proptag/0x39FE001E";
Outlook.Recipients recips = mail.Recipients;
foreach (Outlook.Recipient recip in recips)
{
Outlook.PropertyAccessor pa = recip.PropertyAccessor;
string smtpAddress =
pa.GetProperty(PR_SMTP_ADDRESS).ToString();
Debug.WriteLine(recip.Name + " SMTP=" + smtpAddress);
}
}
But since some time (some weeks) the reference schema at
http://schemas.microsoft.com/mapi/proptag/0x39FE001E
can not be resolved anymore.
Errormessage:
System.Runtime.InteropServices.COMException: http://schemas.microsoft.com/mapi/proptag/0x39FE001E Property unknown or ca not be found.
If I try the URL in a browser I get:
The resource you are looking for has been removed, had its name changed, or is temporarily unavailable.
All examples I can find (for office 2013 and above) are pointing to ressources at http://schemas.microsoft.com/mapi/proptag/SOMETHING
I also could not find any info in forums or oon MSDN that this moved or changed ..
Is anyone else running into this ?
Is ther a known solution or workaroud.
http://schemas.microsoft.com/mapi/proptag/0x39FE001E is not a link, it the actual DASL property name that the PropertyAccessor object expects. The format is different for the fixed and named MAPI properties (e.g. http://schemas.microsoft.com/mapi/id/{00062008-0000-0000-C000-000000000046}/85100003).
You can look at the MAPI properties and their DASL names in OutlookSpy (I am its author - click IMessage button).
Also keep in mind that you should not expect any particular MAPI property to be present - they are not guaranteed to be present and you must expect and handle errors returned by the PropertyAccessor object.
In your particular case, you can are not checking the SMTP address of a sender, you are working wit the message recipients. For the recipients, check if the PR_SMTP_ADDRESS property is there. If not, open the adders entry (Recipient.AddressEntry) and check for that property from the AddressEntry. You can also check for the presence of the PR_EMS_AB_PROXY_ADDRESSES multivalued property (an array is returned). You can so try AddressEntry.GetExchangeUser().PrimarySmtpAddress (be prepared to handle errors and nulls).
Once again, take a look at the message with OutlookSpy to see which property is present.

Outlook ContactItem DeleteEvent

Currently I´m writing a sync tool for GMail contacts and outlook, but there is a little problem:
I need an event in my addin when the user deletes a contact, otherwise the sync tool would detect the missing contact on the outlook side and the tool will create the contact from the google side.
I´m accessing all Outlook contacts from the default folder with this code:
Microsoft.Office.Interop.Outlook.NameSpace mapiNamespace = GetCurrentNamespace();
Microsoft.Office.Interop.Outlook.MAPIFolder contacts = mapiNamespace.GetDefaultFolder(Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderContacts);
IList<Microsoft.Office.Interop.Outlook.ContactItem> items = new List<Microsoft.Office.Interop.Outlook.ContactItem>();
foreach (var contact in contacts.Items)
{
items.Add(contact as Microsoft.Office.Interop.Outlook.ContactItem);
}
return items;
Edit 1:
I already tried to subscribe to an BeforeDelete Event as John Saunders commented, but with no success. When I try to delete a contact in Outlook the event wont get fired.
Code:
Microsoft.Office.Interop.Outlook.NameSpace mapiNamespace = GetCurrentNamespace();
_contactMapiFolder = mapiNamespace.GetDefaultFolder(Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderContacts);
//IList<Microsoft.Office.Interop.Outlook.ContactItem> items = new List<Microsoft.Office.Interop.Outlook.ContactItem>();
this._contacts = new List<Microsoft.Office.Interop.Outlook.ContactItem>();
foreach (var contact in _contactMapiFolder.Items)
{
Outlook.ContactItem item = contact as Microsoft.Office.Interop.Outlook.ContactItem;
item.BeforeDelete += ItemOnBeforeDelete;
this._contacts.Add(item);
}
return this._contacts;
Can anybody provide me an example what events are available for such mapi (especially contact folders) folders are available and how they are working?
It is a really bad idea to set up an event sink on each and every item in a folder.
When Items.ItemRemove even fires, there is no way for you to figure out which item was deleted. You have no choice but to compare the current collection with what you have on the server or in some kind of local cache.
You can try to use Redemption (I am its author) and its RDOItems.ItemRemove event - it passes the value of the PR_INSTANCE_KEY MAPI property from the folder contents table. If you cache the values of the PR_INSTANCE_KEY property for all items ahead of time (you can use RDOITems.MAPITable.ExecSQL for that), you can figure out which item was deleted without looping through all items in the folder.

Outlook Interop ClearSelection Method

I am having difficulties with Interop in a WPF application.
What I actually want to do is drag and drop an Outlook file into my application and extract the attachments and store them. Apart from that I want to read the subject and search for a 4-digit-number which will then be the name of the folder the attachments are to be stored to.
I have been searching the web for solutions that don't use Interop, but I wasn't able to find anything that worked for me.
So I thought 'let's give it a shot' and it sounded pretty simple, because I found so many examples that followed this pattern:
if (e.Data.GetDataPresent("FileGroupDescriptor"))
{
Microsoft.Office.Interop.Outlook.Application app = new Microsoft.Office.Interop.Outlook.Application();
Microsoft.Office.Interop.Outlook.Selection selection = app.ActiveExplorer().Selection;
foreach (object mi in selection)
{
Microsoft.Office.Interop.Outlook.MailItem mailItem = (Microsoft.Office.Interop.Outlook.MailItem)mi;
string subject = "Untitled";
if (!string.IsNullOrEmpty(mailItem.Subject))
{
subject = mailItem.Subject;
MessageBox.Show(subject);
}
}
}
This works, but I have one problem: the selection keeps on growing. I tried the methods RemoveFromSelection and ClearSelection, but they don't work. Everytime I drag a new Outlook item to the surface it keeps displaying all the previous items as well.
Can anybody help me? I'm at a complete loss
Do you handle the Drag event in your application?
If so, try to call the following code in the event handler:
e.Data.GetData(“RenPrivateMessages”);
See Outlook, custom task pane and drag-drop problem for more information.

getting access to outlook exchange global address book

i am building a csharp application and i would like a dropdown list of all users in my outlook global address book (the same one when i click on To: from outlook gui. is this possible to get this progrmaticall? what are the security requirements here?
Security ramifications, in addition to the Outlook dependency left me unable to use this approach, in the past. As a result, I ended up building this in the form of an LDAP query. Another plus is that, (in response to your other question) you will be able to extract contact information because this information is stored in the Active Directory.
DISCLAIMER: It has been almost five years since I have looked at this code, so I'm afraid I no longer fully understand the query. Hopefully it's enough to get you started, however.
DirectoryEntry adFolderObject = new DirectoryEntry();
DirectorySearcher adSearcher = new DirectorySearcher(adFolderObject);
adSearcher.SearchScope = SearchScope.Subtree;
adSearcher.Filter = "(& (mailnickname=*) (| (&(objectCategory=person)(objectClass=user)(!(homeMDB=*))(!(msExchHomeServerName=*)))(&(objectCategory=person)(objectClass=user)(|(homeMDB=*)(msExchHomeServerName=*))) ))";
foreach (SearchResult adObject in adSearcher.FindAll())
{
Console.WriteLine("CN={0}, Path={1}", adObject.Properties["CN"][0], adObject.Path);
}

Categories

Resources