Click here to Skip to main content
Click here to Skip to main content

Utilize Outlook 2010 add-in to copy email attachments to SharePoint

, 16 Mar 2012
Rate this:
Please Sign up or sign in to vote.
This article gives a quick method for looping through all attachments in a single email message and uploading to SharePoint 2007 or 2010.

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;
// The following directive avoids ambiguity between the
// System.IO.File class and Microsoft.SharePoint.Client.File class.
using ClientOM = Microsoft.SharePoint.Client;
using System.IO;
using System.Net;

// below is populated when ATTACH_BY_VALUE for PR_ATTACH_METHOD
const string PR_ATTACH_DATA_BIN = "http://schemas.microsoft.com/mapi/proptag/0x37010102";

// P_LONG..  
const string PR_ATTACH_METHOD = "http://schemas.microsoft.com/mapi/proptag/0x37050003";

// below is populated when ATTACH_EMBEDDED_MSG is for PR_Attach_method
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)
        {
            // first look at PR_ATTACH_METHOD then determine which property to use.
            var attachtypevar = attachment.PropertyAccessor.GetProperty(PR_ATTACH_METHOD);
            int attachtype = Convert.ToInt32(attachtypevar);
            byte[] attachmentData = null;
            if (attachtype == 1)
            {
               // this is a standard object
               attachmentData = 
                 attachment.PropertyAccessor.GetProperty(PR_ATTACH_DATA_BIN) as byte[];

               // pop into memory stream, as the sharepoint object requires that.
               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)
            {
                // this is embedded email , so we can't use BIN.
                // currently the below is not supported per Microsoft.
                // Work around would be to save to disk (eww)
                //  object mi = attachment.PropertyAccessor.GetProperty(PR_ATTACH_DATA_OBJ);
                //  var attachmentDatamsg = attachment.PropertyAccessor.GetProperty(PR_ATTACH_DATA_OBJ);
                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. 

License

This article, along with any associated source code and files, is licensed under The Apache License, Version 2.0

Share

About the Author

Scott Traube
Architect
United States United States
Work as a solution architect for a large manufacturing company in the computer industry.

Comments and Discussions

 
-- There are no messages in this forum --
| Advertise | Privacy | Mobile
Web03 | 2.8.140814.1 | Last Updated 16 Mar 2012
Article Copyright 2012 by Scott Traube
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid