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
- List all attachments of an Outlook item
- Saving all attachments of an Outlook item
- Outlook Attachment security
- Outlook Item Attachment events
- Access Outlook attachments on e-mail reply
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.
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.
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.
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:
37 Comments
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.
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!
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
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?
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.
Hi Ramsha,
Which event do you use to show your dialog box? AttachmentRead?
Hello Ramsha,
It looks like you need to use the BeforeAttachmentPreview event, see https://msdn.microsoft.com/EN-US/library/office/ff862669.aspx.
Hi
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.
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.
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.
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);
}
}
}
}
Hi,
The above question is asked by me.
I am working in office 2007.
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.
Hi i want reply for the above queries…
The am having the same issue like the following link
https://social.msdn.microsoft.com/Forums/sqlserver/en-US/c8a84b07-5591-4202-98cb-2f73d0561c77/c-windows-forms-accessing-only-the-currently-selected-attachment-of-an-outlook-message?forum=outlookdev
And i am also using Outlook 2007. Help me to resolve this issue
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.
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?
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.
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
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.
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.
Hello Andrzej,
Check the source code; find the download link under the Available downloads title.
Is possible open attach files directly, this way if the file is pdf run acrobat reader or excel if it was .xls file
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.
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 .
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.
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.
Thank you for these details!
Hi,
I want to get the path of the attached file . Pls help
And need to know how to get filenames all files attached more than one
Hello,
See MailItem.Attachments at https://msdn.microsoft.com/en-us/VBA/outlook-vba/articles/mailitem-attachments-property-outlook, Attachments object at https://msdn.microsoft.com/en-us/VBA/outlook-vba/articles/attachments-object-outlook and Attachment object at https://msdn.microsoft.com/en-us/VBA/Outlook-VBA/articles/attachment-object-outlook.
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.
Hello Akash,
Please have a look at the following articles, hope they will help:
https://docs.microsoft.com/en-us/visualstudio/vsto/how-to-programmatically-create-an-e-mail-item
https://docs.microsoft.com/en-us/visualstudio/vsto/how-to-programmatically-send-e-mail-programmatically
https://docs.microsoft.com/en-us/visualstudio/vsto/how-to-programmatically-attach-files-to-outlook-e-mail-items
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
Hello Granville,
As far as I remember, the Outlook Object Model does not provide such a possibility to developers, sorry.