Pieter van der Westhuizen

Working with Outlook attachments programmatically: C# code examples

Many Outlook developers have been faced with programmatically accessing and working with Outlook Item attachments. All Outlook items have the Attachments property, which means attachments can be added to MailItem, ContactItem and AppointmentItem items, to name a few.

In this article we’ll explore some facets of handling and interacting with attachments in Outlook. All code examples are written in C#, and of course you are free to re-write them using VB.NET or Visual C++.NET. The samples work for Outlook 2013, 2010 and 2007.

Adding attachments to an Outlook item

For this example, we’ll add a new ribbon tab and button in order to choose and add a new attachment to an e-mail. As usual, we are going to use Add-in Express for Office and net.

Start by adding a new ADXRibbonTab component to the AddinModule designer surface and add a new ribbon group and button to the ribbon tab component.

Adding a new ribbon group with the Add Attachment button to the ribbon tab component

Next, add an OpenFileDialog component to the AddinModule designer surface and set the following properties:

  • Filter = All files|*.*
  • Title = Select Attachment

Select the ribbon button, we’ve added earlier and create a new event handler for its OnClick event by double-clicking next to the event name.

Creating a new event handler for the Add Attachment button's OnClick event

Add the following code to the OnClick event handler:

private void adxAddAttachmentRibbonButton_OnClick(object sender, IRibbonControl control, bool pressed)
{
    Outlook.Inspector currInspector = null;
    Outlook.MailItem mail = null;
    Outlook.Attachments attachments = null;
 
    try
    {
        if (openFileDialog1.ShowDialog() == DialogResult.OK)
        {
            currInspector = OutlookApp.ActiveInspector();
            mail = (Outlook.MailItem)currInspector.CurrentItem;
            attachments = mail.Attachments;
            attachments.Add(openFileDialog1.FileName, Outlook.OlAttachmentType.olByValue);
        }
    }
    finally
    {
        if (attachments != null) Marshal.ReleaseComObject(attachments);
        if (mail != null) Marshal.ReleaseComObject(mail);
        if (currInspector != null) Marshal.ReleaseComObject(currInspector);
    }
}

The code above will display a file dialog to the user with which they can choose a file. The file will then be attached to the e-mail using the Add method of the Attachments collection property of the MailItem object.

List all attachments of an Outlook item

As mentioned previously, all Outlook items have the Attachments property, so in order to get a list of all attachments for an Outlook item, we’ll need to iterate over the Attachments collection. In the following code, we’ll loop through the list of attachments and write the file information to a string.

private void adxListAttachmentsRibbonButton_OnClick(object sender, IRibbonControl control, bool pressed)
{
    Outlook.Inspector currInspector = null;
    Outlook.MailItem mail = null;
    Outlook.Attachments attachments = null;
    string attachmentList = string.Empty;
 
    try
    {
        currInspector = OutlookApp.ActiveInspector();
        mail = (Outlook.MailItem)currInspector.CurrentItem;
        attachments = mail.Attachments;
 
        for (int i = 1; i <= attachments.Count; i++)
        {
            Outlook.Attachment attachment = attachments[i];
            attachmentList += "Display name: " + attachment.DisplayName + "Size: " + attachment.Size + " bytes." + Environment.NewLine;
            Marshal.ReleaseComObject(attachment);
        }
    }
    finally
    {
        if (attachments != null) Marshal.ReleaseComObject(attachments);
        if (mail != null) Marshal.ReleaseComObject(mail);
        if (currInspector != null) Marshal.ReleaseComObject(currInspector);
    }
}

Saving all attachments of an Outlook item


In the next example, we'll prompt the user to select a folder to which they want to save all the current Outlook item's attachments.

Start by adding a new FolderBrowserDialog component to the AddinModule designer surface. Next, we'll add a new button to the ribbon tab we've added earlier. Add the following code in this button's OnClick event handler:

 
private void adxSaveAllRibbonButton_OnClick(object sender, IRibbonControl control, bool pressed)
{
    Outlook.Inspector currInspector = null;
    Outlook.MailItem mail = null;
    Outlook.Attachments attachments = null;
 
    try
    {
        if (folderBrowserDialog1.ShowDialog() == DialogResult.OK)
        {
            currInspector = OutlookApp.ActiveInspector();
            mail = (Outlook.MailItem)currInspector.CurrentItem;
            attachments = mail.Attachments;
 
            for (int i = 1; i <= attachments.Count; i++)
            {
                Outlook.Attachment attachment = attachments[i];
                string path = Path.Combine(folderBrowserDialog1.SelectedPath, attachment.FileName);
                attachment.SaveAsFile(path);
                Marshal.ReleaseComObject(attachment);
            }
        }
    }
    finally
    {
        if (attachments != null) Marshal.ReleaseComObject(attachments);
        if (mail != null) Marshal.ReleaseComObject(mail);
        if (currInspector != null) Marshal.ReleaseComObject(currInspector);
    }
}

Outlook Attachment security

By default Outlook attachments with certain extension are automatically blocked by MS Outlook, for example files with extension .exe or .bat cannot be added to an e-mail message either manually or programmatically via the Outlook Object Model. When the user receives an email with such potentially unsecure attachments, Outlook won't let them open any and display the following warning message instead: "Outlook blocked access to the following potentially unsafe attachments".

Outlook 2007 added a new property called BlockLevel to the Attachment object. This property allows you to programmatically determine the security status of the attachment.  The values for the BlockLevel property are:

  • olAttachmentBlockLevelOpen – The attachment has a restriction which will prevent the user from opening it from Outlook. The user must first save it to disk before opening it.
  • olAttachmentBlockLevelNone – Which means there are no restrictions for this type of attachment and the user can open it directly from Outlook.

Outlook Item Attachment events

Outlook Items expose a number of events with which to interact with attachments. In order to respond to these events, we first need to add a new Outlook Items Events Class to our project.

To respond to the events interacting with attachments, add a new Outlook Items Events Class.

After you've added the class, declare the OutlookItemsEventsClass in the AddinModule.cs class file:

private OutlookItemEventsClass outlookItemEvents = null;

Next, instantiate the OutlookItemEventsClass inside the AddinStartupComplete event:

private void AddinModule_AddinStartupComplete(object sender, EventArgs e)
{
    outlookItemEvents = new OutlookItemEventsClass(this);
}

Add a new ADXOutlookAppEvents object to the AddinModule designer and generate an event handler for the InspectorActivate event.

private void adxOutlookEvents_InspectorActivate(object sender, object inspector, string folderName)
{
    if (canConnect)
    {
        Outlook._Inspector olInsp = (Outlook._Inspector)inspector;
        object item = olInsp.CurrentItem;
 
        if (item is Outlook._MailItem)
        {
            outlookItemEvents.ConnectTo(item, true);
        }
        else
        {
            Marshal.ReleaseComObject(item);
        }
    }
}

Add the following method:

private void ConnectToSelectedItem(object explorer)
{
    Outlook.Selection sel = null;
 
    try
    {
        Outlook._Explorer expl = explorer as Outlook._Explorer;
        sel = expl.Selection;
        if (sel.Count == 1)
        {
            object item = sel[1];
            if (item is Outlook._MailItem)
                outlookItemEvents.ConnectTo(item, true);
            else
                Marshal.ReleaseComObject(item);
        }
    }
    finally
    {
        if (sel != null)
            Marshal.ReleaseComObject(sel);
    }
}

Also, add the following code for the ExplorerActivate, ExplorerClose and ItemSend events:

private void adxOutlookEvents_ExplorerActivate(object sender, object explorer)
{
    ConnectToSelectedItem(explorer);
}
 
private void adxOutlookEvents_ExplorerClose(object sender, object explorer)
{
    int count = 0;
    Outlook._Explorers expls = null;
 
    try
    {
        expls = OutlookApp.Explorers;
        count = expls.Count;
    }
    catch
    {
    }
    finally
    {
        if (expls != null)
            Marshal.ReleaseComObject(expls);
    }
 
    if (count == 0)
        canConnect = false;
}
 
private void adxOutlookEvents_ItemSend(object sender, ADXOlItemSendEventArgs e)
{
    if (outlookItemEvents != null)
        outlookItemEvents.RemoveConnection();
}

Open the OutlookItemEventsClass class, this class enables you to handle the following events:

AttachmentAdd

This event occurs after an attachment has been added to an Outlook item and an instance of the attachment that was added is passed to the event as a parameter.

public override void ProcessAttachmentAdd(object attachment)
{
    Outlook.Attachment attach = attachment as Outlook.Attachment;
    Console.Write("Display name: " + attach.DisplayName + "Size: " + attach.Size + " bytes. Has been added.");
}

AttachmentRead

Occurs after an Outlook attachment has been opened for reading. An instance of the attachment that was added is passed to the event as a parameter.

public override void ProcessAttachmentRead(object attachment)
{
    Outlook.Attachment attach = attachment as Outlook.Attachment;
    Console.Write("Display name: " + attach.DisplayName + ". Has been read.");
}

AttachmentRemove

The event fires when an Outlook attachment has been removed, the attachment that was removed is passed to the event as a parameter.

public override void ProcessAttachmentRemove(object attachment)
{
    Outlook.Attachment attach = attachment as Outlook.Attachment;
    Console.Write("Display name: " + attach.DisplayName + ". Has been removed.");
}

BeforeAttachmentAdd

This event is similar to the AttachmentAdd event, but occurs before the attachment is added to the Outlook item. The attachment that is added is passed as a parameter as well as a Cancel parameter, that when set to 'true' will cancel the operation.

public override void ProcessBeforeAttachmentAdd(object attachment, AddinExpress.MSO.ADXCancelEventArgs e)
{
    Outlook.Attachment attach = attachment as Outlook.Attachment;
    if (attach.FileName.Contains("DoNotAdd"))
        e.Cancel = true;
}

BeforeAttachmentPreview

Occurs before the attachment is previewed. An instance of the attachment and a Boolean to cancel the operation is passed as parameters.

public override void ProcessBeforeAttachmentPreview(object attachment, AddinExpress.MSO.ADXCancelEventArgs e)
{
    Outlook.Attachment attach = attachment as Outlook.Attachment;
    if (attach.FileName.Contains("DoNotPreview"))
        e.Cancel = true;
}

BeforeAttachmentRead

Similar to Outlook's AttachmentRead event, but occurs before the attachment is read from the file system. As with the previous events you also have the option to cancel this operation.

public override void ProcessBeforeAttachmentRead(object attachment, AddinExpress.MSO.ADXCancelEventArgs e)
{
    Outlook.Attachment attach = attachment as Outlook.Attachment;
    if (attach.FileName.Contains("DoNotRead"))
        e.Cancel = true;
}

BeforeAttachmentSave

Occurs before an attachment is saved. This event only occurs when the attachment is saved to the message store, if the user edits the attachments and saves it, the event will not be triggered.

public override void ProcessBeforeAttachmentSave(object attachment, AddinExpress.MSO.ADXCancelEventArgs e)
{
    Outlook.Attachment attach = attachment as Outlook.Attachment;
    if (attach.FileName.Contains("DoNotSave"))
        cancel = true; 
}

BeforeAttachmentWriteToTempFile

This event is triggered before the attachment is written to a temporary file. The attachment that is saved is passed as a parameter as well as a Cancel parameter, that when set to true will cancel the operation.

public override void ProcessBeforeAttachmentWriteToTempFile(object attachment, AddinExpress.MSO.ADXCancelEventArgs e)
{
    Outlook.Attachment attach = attachment as Outlook.Attachment;
    if (attach.FileName.Contains("DoNotSave"))
        cancel = true;
}

Access Outlook attachments on e-mail reply

In the past, we received a question about how to retrieve the attachments of an Outlook e-mail when replying to it. Outlook does not include file attachments when replying to an e-mail, fortunately we can use the ConversationTopic and ConversationIndex properties of the Outlook MailItem object to find the parent e-mail the user is replying to.

All message in a conversation has the same value for the ConversationTopic property and the ConversationIndex property is increased with 5 bytes for each reply. We'll use the OutlookItemsEventsClass, we've added earlier, to intercept the Reply event and gain access to the parent email's attachments.

Open the OutlookItemsEventsClass.cs file and add the following code to the ProcessReply method:

public override void ProcessReply(object response, AddinExpress.MSO.ADXCancelEventArgs e)
{
    string restrictString = string.Empty;
    string conversationIndex = string.Empty;
    Outlook.Folder inboxFolder = null;
    Outlook.Items foundItems = null;
    Outlook.NameSpace session = null;
    Outlook.MailItem mail = null;
 
    try
    {
        mail = response as Outlook.MailItem;
        session = mail.Session;
        conversationIndex = mail.ConversationIndex.Substring(0, mail.ConversationIndex.Length - 10);
        inboxFolder = session.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox) as Outlook.Folder;
        restrictString = "[ConversationTopic] = \"" + mail.ConversationTopic + "\"";
        foundItems = inboxFolder.Items.Restrict(restrictString);
        for (int i = 1; i <= foundItems.Count; i++)
        {
            Outlook.MailItem parentMailItem = foundItems[i] as Outlook.MailItem;
            if (parentMailItem.ConversationIndex == conversationIndex)
            {
                Outlook.Attachments attachments = parentMailItem.Attachments;
                var count = attachments.Count;
                MessageBox.Show("Parent email had " + count + " attachments.");
                Marshal.ReleaseComObject(attachments);
            }
            Marshal.ReleaseComObject(parentMailItem);
        }
    }
    finally
    {
        if (session != null) Marshal.ReleaseComObject(session);
        if (foundItems != null) Marshal.ReleaseComObject(foundItems);
        if (inboxFolder != null) Marshal.ReleaseComObject(inboxFolder);
    }
}

The above code will find the parent email and display a simple message box showing the number of attachments the parent email had.

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

Available downloads:

This sample Outlook add-in was developed using Add-in Express for Office and .net:

Outlook Attachments sample add-in (C#)

37 Comments

  • Rick Leinecker says:

    Hello, I am trying to intercept when the user inserts an attachment. I need to examine the intended attachment, and make a decision on whether to let it happen.

    These examples are different than what I am seeing on my dev box. I just bought add-in express, so I have the latest version. I am using VS 2013.

    Specifically I am looking at the image under the heading “Outlook Item Attachment events” and cannot see that this is the same as I have. Your help is really appreciated.

    Any help you can give so that I can make a decision on allowing users to either attach or not attach is welcome.

  • Pieter van der Westhuizen says:

    Hi Rick,

    You should choose the Outlook Item Events Class – this class will have a method called ProcessBeforeAttachmentAdd.

    The method accepts a parameter that contains the Attachment that represents the file being added as an attachment. You can then use the second ADXCancelEventArgs parameter to either cancel the add or not. e.g.

    Outlook.Attachment attach = attachment as Outlook.Attachment;
    if (attach.FileName.Contains(“DoNotAdd”))
    e.Cancel = true;

    Hope this helps!

  • Ramsha says:

    Hello, This is a very helping explanation of methods, however, I am having a a little problem with ProcessBeforeRead();
    There’s a specific attachment I want to open as a Dialog Box only but the problem is first an empty text file opens up and then the dialog box. I want to eliminate the opening of the text file that opens up in the notepad and get to the dialog box directly.
    My code is:
    if (attach.DisplayName==”Permission Request.txt”)
    displaydialog = true;

    Any ideas that might help?
    Thank You

  • Pieter van der Westhuizen says:

    Hi Ramsha,

    Could you explain a bit more what you would like to accomplish please? What do you mean by you want to open the attachment as a Dialog Box only?

  • Ramsha says:

    Hey Pieter,
    There’s a specific attachment named as “Permission Request” in text file format.I have associated a dialog box with the attachment that when the user clicks open this attachment the dialog box shows up.
    But unfortunately what happens is first a blank text file opens up and if we close that text file then we get the Dialog box.
    I want to get the dialog box in the first place. without the text file opening up.

  • Pieter van der Westhuizen says:

    Hi Ramsha,

    Which event do you use to show your dialog box? AttachmentRead?

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

    Hello Ramsha,

    It looks like you need to use the BeforeAttachmentPreview event, see https://msdn.microsoft.com/EN-US/library/office/ff862669.aspx.

  • Madan says:

    Hi

  • Madan says:

    I want some clarification regarding file attachment. I have multiple attached in a mail, if i select a single attachment from that file(Just select not open the file) how do i find which file is selected among multiple attachments. I want the clear code in C# .Net. Even i tried with options like “Outlook.AttachmentSelection” and “Outlook.Attachments”…etc nothing helps me to find the solution. Please help me to resolve the issue.

  • Madan says:

    I want some clarification regarding file attachment. I have multiple attachment in a mail, if i select a single attachment from that(Just select not open the file) how do i find which file is selected among multiple attachments. I want the clear code in C# .Net. Even i tried with options like “Outlook.AttachmentSelection” and “Outlook.Attachments”…etc nothing helps me to find the solution. Please help me to resolve the issue.

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

    Hello Madan,

    Please have a look at https://www.add-in-express.com/forum/read.php?FID=5&TID=13337. Also make sure you have all updates installed on Office 2016; early versions of Office 2016 showed different behavior, see https://www.add-in-express.com/forum/read.php?SHOWALL_1=1&FID=5&TID=13455#nav_start.

  • Anonymous says:

    Hi Anderi,
    My scenario is totally different. I am working in MVC and my requirement is like if user drag an attachment from outlook mail and drop it in my application the dragged attachment has to store it in particular path. So i used Microsoft.Office.Interop.Outlook.dll and Interop.Microsoft.Office.Core.dll to achieve this. My only doubt is how to check the selected attachment among multiple attachments.
    public ActionResult Outlook()
    {
    Outlook.Application app = new Outlook.Application();
    Outlook.MAPIFolder selectedFolder = app.Application.ActiveExplorer().CurrentFolder;
    if (app.Application.ActiveExplorer().Selection.Count > 0)
    {
    Object selObject = app.Application.ActiveExplorer().Selection[1];
    if (selObject is Outlook.MailItem)
    {
    Outlook.MailItem mailItem = (selObject as Outlook.MailItem);
    itemMessage = “The item is an e-mail message.” +” The subject is ” + mailItem.Subject + “.”;

    for (int i = 1; i <= mailItem.Attachments.Count; i++)
    {
    mailItem.Attachments[i].SaveAsFile(@"E:\TestFileSave\Openfile\" +mailItem.Attachments[i].FileName);
    }
    }
    }
    }

  • Madan says:

    Hi,
    The above question is asked by me.

  • Madan says:

    I am working in office 2007.

  • Madan says:

    Is it possible to get Outlook.AttachmentSelection with out using IRibbonControl or Office.IRibbonExtensibility. Waiting for your reply. It’s very urgent to fix that issue Outlook.AttachmentSelection = null.

  • Madan says:

    Hi i want reply for the above queries…

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

    Hello Madan,

    The AttachmentSelection object was introduced in Outlook 2010; see https://msdn.microsoft.com/en-us/library/office/ff869315(v=office.14).aspx. You can’t use it in Outlook 2007.

  • Barry says:

    Hi,

    I am working on an Outlook add-in to copy attachments from an email to a server and then replace attachment with a url just after the user hits “send”.

    It works but the 20 MB attachment size limit in Outlook is blocking people from adding large attachments which is what my add-in is designed to handle.

    Is there a way for my add-in to prevent Outlook from blocking large attachments with out changing Outlook’s registry settings?

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

    Hello Barry,

    The Outlook object model doesn’t provide a way to bypass this restriction.

    But I’ve noticed that the dialog is shown after the AttachmentRemove event occurs on the corresponding MailItem object. I suppose you can use the event to identify this scenario; the event handler should provide the item being removed. If so, you can try to close the message box programmatically: I suppose you can study message box window attributes using Spy++, and use the attributes to identify the window and send it a message that it treats as a signal to close. Finding the window, learning such a message and sending it, are the tasks that you can try to solve using Spy++ and the Windows API.

  • Byung Kun, Kim says:

    Andrei,

    I tried below, AttachmentRemove occured first before messagebox shown up, but Attachment object in AttachmentRemove event doesn’t give me PathName and FileName,when I access to this property COMException thrown.

    Public Overrides Sub ProcessAttachmentRemove(ByVal Attachment As Object)
    ‘ TODO: Add some code

    Dim attach As Outlook.Attachment = TryCast(Attachment, Outlook.Attachment)

    LF(“DisplayName: {0}. Has been removed.”, AA(attach.DisplayName))
    LF(“PathName: {0}. Has been removed.”, AA(attach.PathName)) ‘Throws exception
    LF(“FileName: {0}. Has been removed.”, AA(attach.FileName)) ‘Throws exception

    End Sub

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

    Hello Kim,

    You get an exception because only a linked attachment has the path and file name; see https://msdn.microsoft.com/en-us/library/office/ff861856.aspx. If an attachment is stored within the MAPI store, it doesn’t have the path and file name – it only has the Attachment.DisplayName property.

  • Andrzej says:

    I see that you are using a flag called canConnect – but never set it to true. I think some code around this flag is missing in this article.

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

    Hello Andrzej,

    Check the source code; find the download link under the Available downloads title.

  • Fernando Sandoval says:

    Is possible open attach files directly, this way if the file is pdf run acrobat reader or excel if it was .xls file

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

    Hello Fernando,

    You can save the attachment to a file programmatically and try to run the file using info they provide at https://stackoverflow.com/questions/10174156/open-file-with-associated-application and https://stackoverflow.com/questions/11365984/c-sharp-open-file-with-default-application-and-parameters.

  • Ranganatha says:

    Dear All ,

    I am facing some issue with inline attachment with text ,

    I have a email like :

    —Some text —–
    –Inline image —
    — some text —
    — inline image —

    i am able to read entire body from exchange server and saved into one table as a nvarchar(max) ,

    Now i am trying to read the DB value and trying to send the email as user typed in my application , but i am not able to succeeded ,

    could any one please help me out in this .

    Thanks in advance .

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

    Hello Ranganatha,

    Sorry, I do not quite understand what exactly problem you are faced with. Do you need to get access to email attachments? Please clarify.

  • Timmy D says:

    In regards to large attachments and the Outlook/Exchange settings blocking large attachments, I have found that when using the Attach button or dragging and dropping files to attach the “BeforeAttachmentWriteToTempFile” event fires BEFORE the message is displayed. This allows you can Cancel attach process before the message is display, no windows API required.

    However the problem is the Attachment Object passed to this Event throws COM exceptions when trying to get the FilePath or GetTemporaryFilePath. It also has a null DisplayName and 0 Size. If I find a solution for this I will post it here.

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

    Thank you for these details!

  • vigneshbabu says:

    Hi,
    I want to get the path of the attached file . Pls help

  • vigneshbabu says:

    And need to know how to get filenames all files attached more than one

  • Akash Gupta says:

    hello all, i am making an outllok addin. what i want is when i open an outlook mail the addin will be able to send the mail attachment to a specific account after the button click.

    i.e. sending the same attachment to a different user using addin.

  • Granville de Fossard says:

    Hi. I’m trying to block attachments that have been dragged in rather than attached. I know they’re not going to contain a temporary file path like files attached from the toolbar, but neither to calendar attachments. Is there some way to determine the difference between an attachment added from the toolbar vs. dragged in from explorer?

    Thanks

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

    Hello Granville,

    As far as I remember, the Outlook Object Model does not provide such a possibility to developers, sorry.

Post a comment

Have any questions? Ask us right now!