Obtain Mail Item details from .MSG attachment - c#

Is it possible to obtain Outlook Mail Item details by dragging and dropping a single attachment from a .MSG file onto a C# application? My application currently separates the contents of a .MSG when this is dropped onto my application, however I want to go a step further and obtain sender, date/time received etc from a single attachment that is part of the .msg. This is what I'm trying at the moment:
Outlook.Application myApp = new Outlook.Application();
object selectedItem = myApp.ActiveExplorer().Selection[1];
Outlook.MailItem item = selectedItem as Outlook.MailItem;
string sender = item.SenderName;
When I try to cast selectedItem as an Outlook.Mail Item nothing happens. Any help with this would be appreciated
Thanks
Chris
Since my initial post I have been looking at other ways in which to obtain the information that Im looking for as I have not been successful with the method above..
I have looked at the following article http://msdn.microsoft.com/en-us/library/aa219397(v=office.11).aspx and implented the code in a test project. I know initially I asked if I could obtain the msg details from the attachement, however if a user drags an attachment from the current open message then I was wondering if it were possible to obtain the message details from the ActiveExplorer method.
At the point where:
myOlSel.Item(x).SenderName & ";"
Outlook prompts me with " A program is trying to access email address..." but at this the message box hangs and I cannot select one of the options. After doing some further reading I understand why this is in place but is there anyway around it?
Thanks
Chris

Maybe the selectedItem is null because there actually is no selected item at index 1?
I have the follwowing at is is working (althou it's with an Appointment item)
Inspector activeInspector = this.OutlookApp.ActiveInspector() as Inspector;
object currentItem = activeInspector.CurrentItem;
if (currentItem != null && currentItem is AppointmentItem)
{
AppointmentItem appItem = currentItem as AppointmentItem;
}
Perhaps you should use Selection[0]?

Related

Adding to Outlook Email Recipient using VSTO before sending email

Looking a bit of advise or direction in regards to VSTO Ribbons with Outlook in C#.
So far I’ve built an Outlook 2010 Ribbon (using TabMail), this Ribbon opens a WinForms window which allows my users to select contacts from a Custom Built Address Book from a SQL database, via a DataGridView.
The users basically select from a datagridview who they want to email, which then gets added to a toLine list.
Application app = new Microsoft.Office.Interop.Outlook.Application();
Mail item item = app.CreateItem((OlItemType.olMailItem));
item.To = toLine;
Item.Display();
This.close();
The downside of using this approach is the user has to build their To List before they actually compose their email.
I’m now trying to make use of TabMailNewMessage. This should allow the user to compose their email, then click the Ribbon icon within the new message and add to their To List from there.
I’ve got the icon showing okay in the TabMailNewMessage, and I’ve got it to open a 2nd Win Form [currently as a test].
I’m a little unsure how to add to the To List of an already open existing mailItem.
At present all I have on the 2nd Win Form is a button, can someone explain how I can click that button and simply add someone to the To List [of this already composed email]. (I don’t have any code behind the button click as I’m not sure what to do)
I also need to make sure that it doesn’t send the email, but simply adds the user to the To List.
Currently using Office 2010, and VS 2013 (with C#).
Hopefully I’m making some sense here.
Thanks
EDIT:
Not sure if its a simple as
Application app = Globals.ThisAddIn.Application;
MailItem mi = (Outlook.MailItem)app.ActiveInspector().CurrentItem;
Mi.Recipients.Add(“joe#email.com”);
This.Close();
The MailItem.Recipients.Add method allows creating a new recipient in the Recipients collection. The name of the recipient can be a string representing the display name, the alias, or the full SMTP email address of the recipient.
using System.Runtime.InteropServices;
// ...
private bool AddRecipients(Outlook.MailItem mail)
{
bool retValue = false;
Outlook.Recipients recipients = null;
Outlook.Recipient recipientTo = null;
Outlook.Recipient recipientCC = null;
Outlook.Recipient recipientBCC = null;
try
{
recipients = mail.Recipients;
// first, we remove all the recipients of the e-mail
while(recipients.Count != 0)
{
recipients.Remove(1);
}
// now we add new recipietns to the e-mail
recipientTo = recipients.Add("Eugene Astafiev");
recipientTo.Type = (int)Outlook.OlMailRecipientType.olTo;
recipientCC = recipients.Add("Somebody");
recipientCC.Type = (int)Outlook.OlMailRecipientType.olCC;
recipientBCC = recipients.Add("eugene.astafiev#somedomain.com");
recipientBCC.Type = (int)Outlook.OlMailRecipientType.olBCC;
retValue = recipients.ResolveAll();
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
}
finally
{
if (recipientBCC != null) Marshal.ReleaseComObject(recipientBCC);
if (recipientCC != null) Marshal.ReleaseComObject(recipientCC);
if (recipientTo != null) Marshal.ReleaseComObject(recipientTo);
if (recipients != null) Marshal.ReleaseComObject(recipients);
}
return retValue;
}
You may find the following articles helpful:
How To: Fill TO,CC and BCC fields in Outlook programmatically
How To: Create and send an Outlook message programmatically
Also, I'd suggest developing an Outlook form region which can be displayed on the same window instead of using a standalone window, see Create Outlook form regions for more information.
Yes, it is as simple as using Application.ActiveInspector.CurrentItem. But you can do better than that - your ribbon button event handler takes IRibbonControl object as a parameter. Cast the IRibbonControl.Context property to Inspector or Explorer (depending on where the button is hosted).
Also keep in mind that in a COM addin there is no reason to create a new instance of the Outlook.Application object (it will be crippled with the security prompts anyway) - use Globals.ThisAddIn.Application

Outlook 2013 Automation Objects: with hotmail EAS account. Move, Copy fails

I understand that user can not move messages cross EAS account boundaries. Moving messages inside the same EAS account is perfectly fine when done manually from Outlook windows, but fails when done through automation objects. What's wrong here?
Outlook.MailItem item = Outlook.Namespace.GetItemFromID(MailItemEntryEid, MailItemStoreEid);
Outlook.MAPIFolder folder = Outlook.Namespace.GetFolderFromID(MAPIFolderEntryEid, MailItemStoreEid);
Outlook.MailItem newItem = item.Move(folder);
both item and folder objects constructed correctly, and belong to the same EAS store, however .Move on the last line is failing with this error:
(0x80040102): Sorry, Exchange ActiveSync doesn't support what you're trying to do.
If I do item.Delete() that moved the item to the Deleted Items folder
The "0x80004005" or "0x80040102" error message when you access a mailbox on an Exchange Server 2010 server by using a MAPI client article describes a similar issue. Do you work with public folders?
Anyway, you can use the Copy method instead and then Delete the source item.
Try to use MailItem.Copy followed by MailItem.Move before calling Save:
set Item = Application.ActiveExplorer.Selection(1)
set Target = Application.Session.GetDefaultFolder(olFolderDrafts)
set newItem = Item.Copy
set newItem = newItem.Move(Target)

VSTO Outlook User Properties (Custom) not syncing

I have the problem that when i add a custom UserProperty to an Outlook MailItem, it does not get synced to other connected Outlooks.
What can i do to force Outlook to sync the whole email?
My overal problem:
I've got a shared Exchange Mailbox, opened on two clients (in Outlook)
I would like to lock a mail item, if it gets opened in one Outlook and show the second Outlook user a message like "The user XX is currently reading this email"
My way to solve the problem:
Creating a Outlook Plugin.
When user "A" is opening the Email, I am adding a "LockingUser" UserProperty to the MailItem object. If user "B" is trying to open the Email, I am first looking if a "LockingUser" Property exists.
I have disabled the cached mode.
I have tried to update the subject of the email: this works perfectly and gets synced immediatly (but is not a solution for my problem)
private void SetLockingUser(Outlook.MailItem mail)
{
var lockingUserProperty = mail.UserProperties.Find("LockingUser");
if (lockingUserProperty != null)
{
MessageBox.Show("Email locked by: " + lockingUserProperty.Value);
return;
}
var identity = System.Security.Principal.WindowsIdentity.GetCurrent();
var username = identity != null ? identity.Name : "";
lockingUserProperty = mail.UserProperties.Add("LockingUser", Outlook.OlUserPropertyType.olText, false, 1);
lockingUserProperty.Value = username;
mail.Save();
}
Please show the relevant snippet of your code and make sure you call MailItem.Save. Also keep in mind that there will always be lag since the changes will take up to a couple minutes to sync to Exchange and then to another user if cached mode is used. You'd be better off using some external sync mechanism instead of a user property.

Unable to change Mail HTML body from VSTO Outook 2007 add-in

The plot:
I am creating an outlook 2007 add-in using VSTO and C# in Visual Studio 2010. The purpose of the add-in is to cause tracking of mails sent to customers. The add-in should insert a tracking code into every outbound mail that later enables it to be recognized and auto archived once the customer replies. My goal is to insert a tracking code as an attribute in the opening tag of the mail's HTML:
<html tracking="ddfwer4w5c45cgx345gtg4g" ...>
This will be done in the event handler of the Application.ItemSend event:
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
this.Application.ItemSend += new Microsoft.Office.Interop.Outlook.ApplicationEvents_11_ItemSendEventHandler(Application_ItemSend);
}
void Application_ItemSend(object Item, ref bool Cancel)
{
if (Item is Outlook.MailItem)
{
Outlook.MailItem mail = (Outlook.MailItem)Item;
mail.HTMLBody = "<html tracking=\"4w5te45yv5e6ye57j57jr6\" ...";
}
}
The problem:
It seem to never change the HTMLBody property. And it does not throw any exceptions. It just does nothing. I rewrote this logic directly in VBA in Outlook, and tried to change the HTMLBody, but it still did not change. How I know it did not change the HTMLBody is by stepping through and hovering over the property to see the current value.
I am however able to make changes to the MailItem.Body property. But since I need to hide the tracking code in some way, the Body property does not help me at all. I also added the MailItem.Save() method after changing the HTMLBody property, but no change.
I thought that perhaps the ItemSend event is to late and I can't change the HTMLBody at that time anymore, but I can't find any event like BeforeSend or alike.
Any ideas would be much appreciated.
I use VB a lot more than C#, but I think I see your problem.
Check the function signature of Application_ItemSend. I see that Cancel is passed by reference; shouldn't Item be passed that way too?
void Application_ItemSend(ref object Item, ref bool Cancel)
{
// ...
}
If Item is passed by value, then your code is only manipulating the copy that was made; the original object isn't being touched. At least, that's how it worked in C++ (but my C++ experience is before .Net, so maybe that doesn't apply).
I had a similar need to put some ids into the message. Seems like Outlook thoroughly scrubs the email before sending it, so by the time it is sent, all the nice hidden properties that you set have been removed.
For my particular need, I ended up instead using the UserProperties element of MailItem. This persists from when the email is created to when it ends up in the Sent Items folder. Perhaps this approach can work for you if the customer reply is tried to the sent email through a conversation?
mailItem.UserProperties.Add("myid", Outlook.OlUserPropertyType.olText);
mailItem.UserProperties["myid"].Value = myid;

Drag'n'drop one or more mails from Outlook to C# WPF application

I'm working on a windows client written in WPF with C# on .Net 3.5 Sp1, where a requirement is that data from emails received by clients can be stored in the database. Right now the easiest way to handle this is to copy and paste the text, subject, contact information and time received manually using an arthritis-inducing amount of ctrl-c/ctrl-v.
I thought that a simple way to handle this would be to allow the user to drag one or more emails from Outlook (they are all using Outlook 2007 currently) into the window, allowing my app to extract the necessary information and send it to the backend system for storage.
However, a few hours googling for information on this seem to indicate a shocking lack of information about this seemingly basic task. I would think that something like this would be useful in a lot of different settings, but all I've been able to find so far have been half-baked non-solutions.
Does anyone have any advice on how to do this? Since I am just going to read the mails and not send anything out or do anything evil, it would be nice with a solution that didn't involve the hated security pop ups, but anything beats not being able to do it at all.
Basically, if I could get a list of all the mail items that were selected, dragged and dropped from Outlook, I will be able to handle the rest myself!
Thanks!
Rune
I found a great article that should do exactly what you need to.
UPDATE
I was able to get the code in that article working in WPF with a little tweaking, below are the changes you need to make.
Change all references from System.Windows.Forms.IDataObject to System.Windows.IDataObject
In the OutlookDataObject constructor, change
FieldInfo innerDataField = this.underlyingDataObject.GetType().GetField("innerData", BindingFlags.NonPublic | BindingFlags.Instance);
To
FieldInfo innerDataField = this.underlyingDataObject.GetType().GetField("_innerData", BindingFlags.NonPublic | BindingFlags.Instance);
Change all DataFormats.GetFormat calls to DataFormats.GetDataFormat
Change the SetData implementation from
public void SetData(string format, bool autoConvert, object data)
{
this.underlyingDataObject.SetData(format, autoConvert, data);
}
TO
public void SetData(string format, object data, bool autoConvert)
{
this.underlyingDataObject.SetData(format, data, autoConvert);
}
With those changes, I was able to get it to save the messages to files as the article did. Sorry for the formatting, but numbered/bulleted lists don't work well with code snippets.
I found a lot of solutions suggesting you use the “FileGroupDescriptor” for all the file names and the “FileContents” on the DragEventArgs object to retrieve the data of each file. The “FileGroupDescriptor” works fine for the email message names, but “FileContents” returns a null because the implementation of the IDataObject in .Net cannot handle the IStorage object that is returned by COM.
David Ewen has a great explanation, excellent sample and code download that works great at http://www.codeproject.com/KB/office/outlook_drag_drop_in_cs.aspx.
In your Xaml you need to set up your Event:
<TextBlock
Name="myTextBlock"
Text="Drag something into here"
AllowDrop="True"
DragDrop.Drop="myTextBlock_Drop"
/>
Once you have Set AllowDrop = True and Set you drop event then go to the code behind and set up your event:
private void myTextBlock_Drop(object sender, DragEventArgs e)
{
// Mark the event as handled, so TextBox's native Drop handler is not called.
e.Handled = true;
Stream sr;
//Explorer
if (e.Data.GetDataPresent(DataFormats.FileDrop, true))
//Do somthing
//Email Message Subject
if (e.Data.GetDataPresent("FileGroupDescriptor"))
{
sr = e.Data.GetData("FileGroupDescriptor") as Stream;
StreamReader sr = new StreamReader(sr2);//new StreamReader(strPath, Encoding.Default);
//Message Subject
string strFullString = sr.ReadToEnd();
}
}
If you wish to break it down further you can use:
FILEDESCRIPTOR or FILECONTENTS as outline in the following article
your other option is to tie into outlooks MS Office Primary Interop Assemblies and break the message apart that way.
I think Shell Style Drag and Drop in .NET (WPF and WinForms) can help you. Once you can respond to drag drop using the COM Interfaces, you should be able to get the data out of outlook.
I assume that you have an Exchange server running behind Outlook.
What you can do is to retrieve the mail from the Exchange server and store its location in your database based on the mail's EntryID and StoreID. Here's a VB.Net snippet:
Imports Microsoft.Office.Interop
Public Class OutlookClientHandler
Private _application As Outlook.Application
Private _namespace As Outlook.NameSpace
Public Sub New()
If Process.GetProcessesByName("outlook".ToLower).Length > 0 Then
_application = New Outlook.Application
Else
Dim startInfo As ProcessStartInfo = New ProcessStartInfo("outlook.exe")
startInfo.WindowStyle = ProcessWindowStyle.Minimized
Process.Start(startInfo)
_application = New Outlook.Application
End If
End Sub
' Retrieves the specified e-mail from Outlook/Exchange via the MAPI
Public Function GetMailItem(ByVal entryID as String, ByVal storeID as String) As Outlook.MailItem
_namespace = _application.GetNamespace("MAPI")
Dim item As Outlook.MailItem
Try
item = _namespace.GetItemFromID(entryID, storeID)
Catch comex As COMException
item = Nothing ' Fugly, e-mail wasn't found!
End Try
Return item
End Function
End Class
I guess you are comfortable with using the MAPI, otherwise you can read up here:
http://msdn.microsoft.com/en-us/library/cc765775(v=office.12).aspx
To retrieve the selected e-mails from outlook:
Public Function GetSelectedItems() As List(Of Object)
Dim items As List(Of Object) = New List(Of Object)
For Each item As Object In _application.ActiveExplorer().Selection
items.Add(item)
Next
Return items
End Function
After you've retrieved the e-mails from Outlook you can just push them into your database! Save their EntryID and StoreID (you might want to store their parent's (the folder's) EntryID and StoreID as well).

Categories