Pieter van der Westhuizen

Office 365 – Save Outlook e-mails & attachments to SharePoint Online programmatically

If you’re following Ty’s Office 365 Newswires and read this article about Microsoft already having sold five million Office 365 seats in roughly two and a half months, I’m sure you would agree with me that Office 365 is set to change, if not revolutionize the way people use and interact with Microsoft Office.

Of course this opens a whole world of possibilities to developers and even more so for the few, the proud Office developers. I love to dream up ways to integrate Microsoft Office with different applications and online services and in today’s post I’ll show you how to write a Microsoft Outlook Add-in that will save an e-mail’s attachments and/or the entire e-mail to an Office 365 hosted SharePoint Online list.

Let’s get started by creating a new ADX COM Add-in in Visual Studio 2010 with Add-in Express for Office and .NET.

Creating a new COM Add-in in Visual Studio 2010

When prompted select Visual C# and Microsoft Office 2010.

Selecting Visual C# and Microsoft Office 2010

This add-in will only be available in Microsoft Outlook so make sure it is the only selected application in the list of supported applications.

Selecting Outlook in the list of supported applications

After completing the wizard, add a new ADXBackstageView component to the AddinModule designer surface and also add two ADXBackstageFastCommandButton controls. Set the following properties for the first button

  • Name: adxButtonSaveAttachments
  • Caption: Save Attachments to SharePoint Online
  • InsertAfterIdMso : FileSaveAs
  • Ribbons: OutlookMailRead

And set the following for the second button:

  • Name: adxButtonSaveEmail
  • Caption: Save E-mail to SharePoint Online
  • InsertBeforeIdMso : SaveAttachments
  • Ribbons: OutlookMailRead

With all the properties set, your design should resemble the following image:

In-place visual designer for the ADXBackstageview component

When I first started with this article, I had the intention of uploading the files using the SharePoint Foundation 2010 Managed Client Object Model. Unfortunately, after numerous attempts and some further research I found it was just not as simple as the examples on that page indicated it should be. The problem is that when you need to access the SharePoint object from outside Office 365 or outside the browser, you need to use active authentication.

I’m not going to go into much detail about this, but I recommend you read Wictor Wilen’s article on this topic. I also based this example on the solution he suggested.

Ok, with that out of the way, let’s add the MSOnlineClaimsHelper.cs and WcfClientContracts.cs classes that Wictor wrote about (you can download the files from the article mentioned earlier, it is also available in this article’s sample project).

Next, we’ll add our own SharePointHelper.cs class. The code listing for this class is as follows:

using System;
using System.IO;
using System.Net;
using Microsoft.SharePoint.Client;
using Wictor.Office365;
 
namespace SaveToSharePoint
{
public class SharePointHelper
{
    public string Username { get; set; }
    public string Password { get; set; }
    public string Url { get; set; }
    public MsOnlineClaimsHelper ClaimsHelper { get; set; }
 
    public SharePointHelper(string username, string password, string url)
    {
        this.Username = username;
        this.Password = password;
        this.Url = url;
        this.ClaimsHelper = new MsOnlineClaimsHelper(url, username, password);
    }
 
    public HttpStatusCode UploadFile(string source, string destination)
    {
        using (ClientContext context = new ClientContext(this.Url))
        {
            //destination == "/Shared Documents/filename.extension"
            string fileUrl = this.Url + destination;
            FileStream fileStream = System.IO.File.OpenRead(source);
            int dataLength = Convert.ToInt32(fileStream.Length);
            byte[] data = new byte[dataLength];
            fileStream.Read(data, 0, dataLength);
 
            HttpWebRequest httpRequest =
				HttpWebRequest.Create(fileUrl) as HttpWebRequest;
            httpRequest.Method = "PUT";
            httpRequest.Accept = "*/*";
            httpRequest.ContentType = "multipart/form-data; charset=utf-8";
            httpRequest.CookieContainer = this.ClaimsHelper.CookieContainer;
            httpRequest.AllowAutoRedirect = false;
            httpRequest.UserAgent =
				"Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0)";
            httpRequest.Headers.Add("Accept-Language", "en-us");
            httpRequest.Headers.Add("Translate", "F");
            httpRequest.Headers.Add("Cache-Control", "no-cache");
            httpRequest.ContentLength = fileStream.Length;
 
            using (Stream stream = httpRequest.GetRequestStream())
            {
                stream.Write(data, 0, dataLength);
            }
 
            HttpWebResponse response = (HttpWebResponse)httpRequest.GetResponse();
            return response.StatusCode;
        }
    }
}
}

Save the class and switch back to the AddinModule designer and select the BackstageView component we’ve added earlier. Select the “Save Attachments to SharePoint Online” button and add an event handler for its OnClick event. Add the following code to the event handler:

private void adxButtonSaveAttachments_OnClick(object sender, IRibbonControl control)
{
    Outlook.Inspector currInspector = null;
    Outlook.MailItem currMail = null;
    Outlook.Attachments attachments = null;
    int numberOfAttachments = 0;
    Dictionary<string , string> files = new Dictionary<string , string>();
    SharePointHelper spHelper = null;
 
    try
    {
        currInspector = OutlookApp.ActiveInspector();
        if (currInspector.CurrentItem is Outlook.MailItem)
        {
            currMail = (Outlook.MailItem)currInspector.CurrentItem;
            attachments = currMail.Attachments;
            numberOfAttachments = attachments.Count;
            if (numberOfAttachments > 0)
            {
                spHelper = new SharePointHelper(
					"your@email.com",
					"YourPassword",
					"https://yourdomain.sharepoint.com/sites/TeamSite");
                for (int i = 1; i < = numberOfAttachments; i++)
                {
                    Outlook.Attachment attachment = attachments[i];
                    string filePath = Path.Combine(
						Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
						attachment.FileName);
                    attachment.SaveAsFile(filePath);
                    files.Add(attachment.FileName, filePath);
                    Marshal.ReleaseComObject(attachment);
                }
 
                foreach (var file in files)
                {
                    System.Net.HttpStatusCode status =
						spHelper.UploadFile(file.Value, "/Shared Documents/" + file.Key);
                    if (status != System.Net.HttpStatusCode.Created)
                        MessageBox.Show(file.Key + " failed to upload.");
                }
            }
        }
    }
    finally
    {
        if (attachments != null)
            Marshal.ReleaseComObject(attachments);
        if (currMail != null)
            Marshal.ReleaseComObject(currMail);
        if (currInspector != null)
            Marshal.ReleaseComObject(currInspector);
    }
    MessageBox.Show("Done");
}

This code will check whether the current open e-mail has attachments and then save those attachments to the Shared Documents library in SharePoint.

Next, add an event handler for the “Save E-mail to SharePoint Online” button and add the following code to it:

private void adxButtonSaveEmail_OnClick(object sender, IRibbonControl control)
{
    Outlook.Inspector currInspector = null;
    Outlook.MailItem currMail = null;
    SharePointHelper spHelper = null;
    string fileName = string.Empty;
 
    try
    {
        currInspector = OutlookApp.ActiveInspector();
        if (currInspector.CurrentItem is Outlook.MailItem)
        {
            spHelper = new SharePointHelper(
				"your@email.com",
				"YourPassword",
				"https://yourdomain.sharepoint.com/sites/TeamSite");
            currMail = (Outlook.MailItem)currInspector.CurrentItem;
            fileName = String.Format(
				"{0} - {1}.msg",
				SafeFileName(currMail.SenderName),
				SafeFileName(currMail.Subject));
            string filePath = Path.Combine(
				Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
				fileName);
            currMail.SaveAs(filePath, Outlook.OlSaveAsType.olMSG);
 
            System.Net.HttpStatusCode status =
				spHelper.UploadFile(filePath, "/Shared Documents/" + fileName);
            if (status != System.Net.HttpStatusCode.Created)
                MessageBox.Show(fileName + " failed to upload.");
        }
    }
    finally
    {
        if (currMail != null)
            Marshal.ReleaseComObject(currMail);
        if (currInspector != null)
            Marshal.ReleaseComObject(currInspector);
    }
    MessageBox.Show("Done");
}

This code essentially does the same as the previous listing, except that instead of only saving the e-mail’s attachments it will save the entire e-mail to the SharePoint library.

Build, register and run your project and open an e-mail in Outlook that has attachments.

Open an e-mail in Outlook that has attachments

When you click on the File Menu you should see the two buttons we’ve added earlier:

Two custom buttons in Outlook Backstage view

Click on the “Save Attachment to SharePoint Online” button. It should take a few seconds and when you view the Shared Documents library in SharePoint you should see all the files that was attached to the e-mail.

The attachments saved in the Shared Documents library

Finally, click on the “Save E-mail to SharePoint Online” button. The entire e-mail should now be saved in the Shared Documents library.

The entire e-mail saved in the Shared Documents library

Thank you for reading. Until next time, keep coding!

Available downloads:

The sample COM Add-in was developed using Add-in Express for Office and .NET:

C# sample project

41 Comments

  • Petrus says:

    Hi there,I just bought Add-in Express for Office and .NET, and i have a small question relating this example, what happens after you press the “Save E-mail to SharePoint Online” button, do you get a total tree of Folders you can upload to, or does everything Need to be prespecified

  • Pieter van der Westhuizen says:

    Hi Petrus,
    Welcome aboard!
    When saving the email to SharePoint you wont be prompted to choose the save location. In this example it will be saved to the Shared Documents library in SharePoint. The code that does the work is :

    spHelper.UploadFile(filePath, “/Shared Documents/” + fileName);

    Thank you for your comment!

  • Petrus says:

    Hi Pieter, Thanks alot for your reply,
    I have currently been put upon the Task of creating such an Addin that allows users to save emails on SharePoint over a button click (which is found on the Toolbar), only that i also have to Show them the Basic SharePoint Tree of Folders that they can choose from.
    My question (I’m a Young beginner, i hope the question isn’t stupid):
    Could i make such a Thing possible on the example Code through small modifications? – (Do I Need to configure a Webservice ?)
    Thanks in Advance, I’m looking Forward to your Answer.

  • Alan says:

    My Office is in German, and i don’t see the 2 Buttons, could it be because of that?

  • Pieter van der Westhuizen says:

    Hi Petrus,

    It should be possible. All you need to do is display a list of SharePoint libraries to the user and then change the sample code to use that library instead of the one hard-coded in the example.
    A good intro on programming SP lists can be found here: https://msdn.microsoft.com/en-us/library/dd490727%28v=office.12%29.aspx

    Good luck!

  • Pieter van der Westhuizen says:

    Hi Alan,

    I doubt it could be because your Office is in German. Did you set the correct values for the InsertBeforeIdMso properties?

  • Alan says:

    Hello Pieter,
    I just checked the InsertBeforeIdMso on both “Save Attachments to SharePoint Online” and “Save E-mail to SharePoint Online”

    The InsertBeforeIdMso Properties for “Save Attachments to SharePoint Online” is simply blank ( ? what should i do)

    and the Properties for “Save E-mail to SharePoint Online” on InsertBeforeIdMso says: SaveAttachments

  • Pieter van der Westhuizen says:

    Hi Alan,

    Check the article carefully. The adxButtonSaveAttachments button’s InsertAfterIdMso property should be FileSaveAs and the adxButtonSaveEmailInsert button’s BeforeIdMso property should be SaveAttachments

  • Alan says:

    Hi Pieter,

    Checked it, everything is as you say,
    It doesn’t work though, do you have any tipps as to where i should look next?,
    I am using Outlook 2010, thnx for your help

  • Pieter van der Westhuizen says:

    Hi Alan,

    Ok, please download the sample project to check how I’ve done it. Maybe you just missed something somewhere :)

  • Alan says:

    Hi Pieter,

    I’m deeply sorry for having invoked a missunderstanding.
    I’m already using the sample, I bought Add-in Express, and then loaded the Project, had a Little Trouble with the SharePoint references, since i don’t have it installed on my Windows 8, and I’m trying to use it for Office365,which i later fixed after downloading the “SharePoint Foundation 2010 Client Object Model Redistributable”.
    I rebuild my Project and press the Debugg button, Outlook starts, and i select an email(which has an attachment) and then go to File, but don’t see the two buttons

  • Pieter van der Westhuizen says:

    Hi Alan,
    Do you only select the e-mail or do you double-click it and the email Inspector window opens?
    The buttons will be on the e-mail inspector window’s File menu.

  • Alan says:

    Hi Pieter,
    I tried both of them now,
    out of despair i restarted reading the articel carefully again,
    and i see that besides Building and Debugging you also say Register.
    Quote “Build, register and run your Project”, how do you Register?,
    maybe it’s that why i can’t see them

  • Pieter van der Westhuizen says:

    Aah yes. That would be the problem. To register your project, you can right-click on the project in Solution Explorer and choose Register ADX Project from the context-menu.

  • Alan says:

    THANK YOU A MILLION TIMES :D

  • Petrus says:

    Hi Pieter,

    I have one more question regarding the issue,
    to be quite correct i’m actually looking for some tips which i might gather from a more experienced Person, such as you.
    I’m using your sample, which is working quite well, though I Need to connect to an Office 365 through ADFS(only E-Mail required),
    which if basically done over the browser, takes you from the Standard Office 365 Login page(after giving in the E-Mail) and Redirects you to a new page where it asks you to enter the Username,
    do you have any ideas on how to go for this Thing in the sample:
    -Insert E-Mail
    -Let the addin wait for the Redirection
    and then give in Credentials(Username) which (after that) would take me to the page (i think this happens automatically) which i requested in the first place.
    Always greatefull for your help!

  • Pieter van der Westhuizen says:

    Hi Petrus,

    Unfortunately, I have never done what you are describing. But it sounds similar to using OAuth.
    I’ve done some digging and found 2 links that might help you:

    https://stackoverflow.com/questions/11295953/claim-auth-from-adfs
    and
    https://jwillmer.de/blog/2013/01/04/sharepoint-online-with-adfs-authentication/

    Hope this helps! Let us know if you get it working and how you did it please.

  • Anderson says:

    Hi there Pieter,
    I am currently trying to modify the Code so i can use the it’s capabilities on an ADXRibbon Tab (Group – Button),
    but i’m also suffering from terrible problems while i’m trying to do that.
    I’ve set up the button (that is supposed to save a *selected e-mail to SharePoint)visualy and everything, but when I’m in the code and I’m Trying to copy everything you did for the “mailReadBackstageView” i get into some issues in the beginning, ex:

    //|under Initialize Component| i try to add the following:
    this.SaveButton.OnClick += new AddinExpress.MSO.ADXRibbonOnClick_EventHandler(this.SaveButton_OnClick);

    after that i copy your whole method and change the name but it gives me an Error back saying:
    “An implicit conversion from type ‘AddinExpress.MSO.ADXRibbonOnClick_EventHandler’ in ‘AddinExpress.MSO.ADXRibbonOnAction_EventHandler’ is not possible.”
    What can i Do? I try to ask this in the Forum but it seems i can’t post a new thread.
    thanks for your Help

  • Pieter van der Westhuizen says:

    Hi There,

    Mmm…when you generate the event handler for the button’s click event, did you select it in the designer and double-click next to the OnClick event in the properties window?
    This will generate the event handler code for you.

  • Anderson says:

    Hi Pieter,
    Just did what you said,
    i debugged, and while having an email selected in outlook i pressed my Ribbon button.
    Visual Studio threw me directly at this part of the Method (which i have simply copied from yours)

    “if (currInspector.CurrentItem is Outlook.MailItem)”
    could this be because in your example you have to open an email in the email Inspector window (if yes, please give me some guidance), if not, what could it be

    Thanks so much for your help!

  • Pieter van der Westhuizen says:

    You will receive an error if you do not have an e-mail open. The sample was done with a button on the ribbon of an open email’s window(Inspector).
    However, you can have a button on the main Outlook window(Explorer), the user then needs to select an e-mail and click the button.

    You will then need to get the current selection:

    Outlook._Explorer currExplorer = OutlookApp.ActiveExplorer() as Outlook._Explorer;

    You can then get the selected e-mail(s):

    Outlook.Selection selection = currExplorer.Selection;

    You can then loop through the selection and process each e-mail:

    if (selection != null && selection.Count > 0)
    {
    for (int i = 1; i <= selection.Count; i++)
    {
    if (selection[i] is Outlook.MailItem)
    {
    // Check for attachments and save
    }
    }
    }

    Hope this helps!

  • Anderson says:

    You are the Best!

  • Hardy says:

    Hi Petrus,

    I am new to sharepoint, I need to do the exact same thing which you had to do. Could you please help me do it ,if you have already found something on it.

  • Pieter van der Westhuizen says:

    Hi Hardy,

    If you need to save files or e-mail attachments to SharePoint, you can follow the steps detailed in the article.
    You can also download the source code for the article here

    Hope this helps!

  • Anil Rana says:

    would code be applicable in Outlook 2013 and VS 2013

  • Anil says:

    Hi Pieter,

    Anil again.. I tried you code in vs2013 for Outlook 2013 and it deployed fine. However, I could not see the options for saving email to SharePoint and saving attachments to share point site. Any ideas..

    Thanks

  • Pieter van der Westhuizen says:

    Hi Anil,

    The option to save the email and/or attachments to SharePoint should be visible in the e-mail Inspector/Windows’s backstage view or File menu as illustrated in this image:
    https://www.add-in-express.comhttps://cdn.add-in-express.com/blog-upload/images/2012/outlook-email-sharepoint/custom-buttons.png

    Do you see those options?

  • Vamsi says:

    Hi Pieter,

    This is avery nice post. However I like to know will it be possible to create add-in for outlook 2013 and saves email into SharePoint 2007 library.

    Regards,
    Vamsi.

  • Pieter van der Westhuizen says:

    Hi Vamsi,

    To be honest, I have not worked with SP2007, so unfortunately I would not be able to tell you how to accomplish the same with the SP 2007 api.
    I suggest having a look at the SharePoint 2007 SDK documentation. The Outlook bit of adding buttons and saving attachments will remain the same.

    Good luck!

  • rahul says:

    how to save attachments in my local folder directly.

  • Pieter van der Westhuizen says:

    Hi rahul,

    If you want to save the currently open email’s attachments you can nuse the following code:

    Outlook.Inspector currInspector = null;
    Outlook.MailItem mail = null;
    Outlook.Attachments attachments = null;
    Outlook.Attachment attachment = null;
    try
    {
    currInspector = OutlookApp.ActiveInspector();
    if (currInspector.CurrentItem is Outlook.MailItem)
    {
    mail = currInspector.CurrentItem as Outlook.MailItem;
    attachments = mail.Attachments;
    for (int i = 1; i <= attachments.Count; i++)
    {
    attachment = attachments[i];
    attachment.SaveAsFile(@"C:\Temp\" + attachment.FileName);
    }
    }
    }
    finally
    {
    if (attachment != null)
    Marshal.ReleaseComObject(attachment);
    if (attachments != null)
    Marshal.ReleaseComObject(attachments);
    if (mail != null)
    Marshal.ReleaseComObject(mail);
    if (currInspector != null)
    Marshal.ReleaseComObject(currInspector);
    }

  • sabarish says:

    Just wondering if you have Visual basic version of this code.

  • Andrei Smolin (Add-in Express Team) says:

    Hello Sabarish,

    You can use any C# to VB.NET converter available online. See e.g. https://converter.telerik.com/.

  • Mattias Jasic Modin says:

    Hi,

    Would it be possible to use Adx to use drag and drop to Internet Explorer like this:
    https://outlook2web.com/

    Regards,
    Mattias

  • Andrei Smolin (Add-in Express Team) says:

    Hello Mattias,

    No such possibilities are built in Outlook, browsers and Add-in Express. We could develop such a solution in the framework of our custom development services, see https://www.add-in-express.com/custom-development/index.php.

  • Arthur says:

    This not working for a SharePoint 2013 or 2016 ? What do I need change to make this work with local SharePoint ?
    if (!string.IsNullOrEmpty(cookies.FedAuth))

  • Dmitry Kostochko (Add-in Express Team) says:

    Hi Arthur,

    I think you need to pass correct values (username, password and url) to the SharePointHelper constructor so that the code can access your local SharePoint.

  • Rajkumar Pawar says:

    Hi,
    Is there a way to do the same task using vba(visual basic) based on mail subject line

    Thanks!

  • Andrei Smolin (Add-in Express Team) says:

    Hello Rajkumar,

    I don’t know how to send an HTTP request and process it using VBA. The remaining parts look absolutely doable.

  • Naresh says:

    Hi ,

    Currently,i am getting body attachments along with mail attachments in mail inspector.Do we have any provision to get only attached attachments except the body attachments?

    Regards,
    Naresh

  • Andrei Smolin (Add-in Express Team) says:

    Hello Naresh,

    Have a look at https://www.add-in-express.com/forum/read.php?PAGEN_1=3&FID=5&TID=10590.

Post a comment

Have any questions? Ask us right now!