Introduction
A quick way to save attachments to SharePoint 2010 from
the Outlook 2010 add-in. (Note, I am successfully using this code with
SharePoint 2007, although it is not supported.)
Using the Code
My example starts with the Microsoft Ribbon example. This allows you to easily add a right click event to email items. Please download and start with this ribbon example from Microsoft: http://msdn.microsoft.com/en-us/library/ee692172.aspx.
You also need to have the SharePoint foundation client object model DLLs: http://www.microsoft.com/download/en/details.aspx?id=21786.
And this article shows you how to properly reference it from your solution: http://msdn.microsoft.com/en-us/library/ee857094.aspx#SP2010ClientOM_Using_the_Managed_Client_Object_Model.
Here is where the DLLs get installed exactly: C:\Program Files\Common Files\microsoft shared\SharePoint Client\Microsoft.SharePoint.Client.dll.
Now! Finally, my stuff..
Modify the explorer.xml file as follows to enable the right click event. You can add as many buttons as you want, very cool.
I left a submenu and secondary button as an example of how to do that.
<contextMenus>
<contextMenu idMso="ContextMenuMailItem">
<menuSeparator id="MySeparator" />
<menu id="MySubMenu" label="submenu">
<button id="MyContextMenuMailItem4"
label="Attachment to Sharepoint"
onAction="LaunchAttachUp"/>
<button id="MyContextMenuMailItem5"
label="Meeting Invite"
onAction="CreateMeeting"/>
</menu>
</contextMenu>
</contextMenus>
Now open RibbonXAddin.cs and add the LaunchAttachUp
method. Note I'm validating the context. All this really does is determine the specific email
you right clicked on, and then calls the function to upload to SharePoint. Note, I have for this example a fixed site. If you have a subfolder in the Shared Documents Library,
you would add that to the end of that line as: /sites/YOURSITENAME/Shared Documents/subfolder1/subsubfolder/.
public void LaunchAttachUp(Office.IRibbonControl control)
{
if (control.Context is Outlook.Selection)
{
Outlook.Selection selection =
control.Context as Outlook.Selection;
if (selection.Count == 1)
{
if (selection[1] is Outlook.MailItem)
{
Outlook.MailItem oMail = selection[1] as Outlook.MailItem;
ShareAttach sa = new ShareAttach();
sa.AttachmentSharepoint(oMail, "http://SITEURLFORSHAREPOINT.COM",
"/sites/YOURSITENAME/Shared Documents/");
}
}
}
}
Now the above calls the following:
using Outlook = Microsoft.Office.Interop.Outlook;
using System.Runtime.InteropServices;
using System.Collections;
using Microsoft.SharePoint.Client;
using ClientOM = Microsoft.SharePoint.Client;
using System.IO;
using System.Net;
const string PR_ATTACH_DATA_BIN = "http://schemas.microsoft.com/mapi/proptag/0x37010102";
const string PR_ATTACH_METHOD = "http://schemas.microsoft.com/mapi/proptag/0x37050003";
const string PR_ATTACH_DATA_OBJ = "http://schemas.microsoft.com/mapi/proptag/0x3701000D";
public void AttachmentSharepoint(Outlook.MailItem mailItem,
string clientContextURL, string sitelibfolder)
{
if (mailItem != null)
{
var attachments = mailItem.Attachments;
foreach (Outlook.Attachment attachment in attachments)
{
var attachtypevar = attachment.PropertyAccessor.GetProperty(PR_ATTACH_METHOD);
int attachtype = Convert.ToInt32(attachtypevar);
byte[] attachmentData = null;
if (attachtype == 1)
{
attachmentData =
attachment.PropertyAccessor.GetProperty(PR_ATTACH_DATA_BIN) as byte[];
MemoryStream theMemStream = new MemoryStream();
theMemStream.Write(attachmentData, 0, attachmentData.Length);
theMemStream.Position = 0;
try
{
bool overwrite = false;
ClientContext clientContext = new ClientContext(clientContextURL);
using (theMemStream)
ClientOM.File.SaveBinaryDirect(clientContext, sitelibfolder +
attachment.FileName, theMemStream, overwrite);
}
catch (Exception ex)
{
MessageBox.Show("Sharepoint URL issues. " + ex.Message);
}
}
else if (attachtype == 5)
{
MessageBox.Show(attachment.FileName +
" - is not a supported attachment format for auto-upload.");
}
}
}
}
So the use case is as follows. User opens Outlook and is within Mail view of the primary active
Outlook Explorer.
You would right click an email and see your custom button, which you added in the
XML, which will say attachment to
SharePoint.
That will then upload all attachments on that one specific email message to your
SharePoint instance specified in the code.
Points of Interest
This works on all file types except embedded emails, i.e., I have an email with
four attachments, three are zip, xls, doc, but the forth is a
.msg.
The .msg won't work. You can code around that problem, but my implementation only identifies that it is a
.msg, it won't actually pop it to SharePoint.
This is a feature of a larger effort I'm working on. I have a conversation sweeper, a custom classification/attribute email tagging feature (with full search
on classes and their attributes!), quick appointment setup based on email TO/CC folks, etc.
I simplified my implementation for this example. My version actually brings up a tiny Windows form that has persisted
SharePoint
sites (so you don't have to type them in each time). It persists them on a hidden storage item. I'll throw in an example of saving data to/from that for good measure.
You don't need the code below for my above example though.
private void AddtoStorage(string storageIdentifier, string storageContent)
{
if (!String.IsNullOrEmpty(storageIdentifier) && !String.IsNullOrEmpty(storageContent))
{
Outlook.MAPIFolder folder = Globals.ThisAddIn.Application.GetNamespace(
"MAPI").GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
Outlook.StorageItem storageitem = folder.GetStorage(storageIdentifier,
Outlook.OlStorageIdentifierType.olIdentifyBySubject);
storageitem.Body = storageContent;
storageitem.Save();
}
}
private string GetfromStorage(string storageIdentifier)
{
if (!String.IsNullOrEmpty(storageIdentifier))
{
Outlook.MAPIFolder folder = Globals.ThisAddIn.Application.GetNamespace(
"MAPI").GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox);
Outlook.StorageItem storageitem = folder.GetStorage(storageIdentifier,
Outlook.OlStorageIdentifierType.olIdentifyBySubject);
try
{
string bodycontent = storageitem.Body.ToString();
return bodycontent;
}
catch (Exception e)
{
return "";
}
}
else
{
return "";
}
}
History
Example for SharePoint uploaded on 3/15. Removed two lines of code not needed for this example and actually make it incorrect for this implementation. Cleaned
title. Clarified that Foundation is geared towards 2010 and not 2007.