Working with Outlook mail items: how to create, delete, access & enumerate
Mail items are the featured player of Outlook… email! Sure, contacts and appointments are regulars but email receives the most attention. We are addicted to the stuff. I bet you check on the toilet don’t you. That’s gross.
Anyway, as an Outlook plug-in developer, you need to know the basics. In football it’s called blocking and tackling. In Outlook development, we can call it working with Outlook email items.
In the Outlook object model, an email is known as a MailItem. Today, I’ll cover the blocking and tackling with email:
- How to access and enumerate mail items
- How to create and send email
- How to delete a mail item
- How to attach files to an email
- How to save and delete all attachments from all emails in the inbox
- Useful events for working with mail items
Life is short and the day is long. Let’s get to it.
Note. I’m assuming you know how to create an ADX COM Add-in project in Visual Studio using Add-in Express for Office and .net. If not, look back at a few recent blog posts. We explain how to do this all the time.
How to access & enumerate mail items
Emails reside in Outlook folders. The folder hierarchy is different per user but how you access & enumerate email items is always the same. This sample shows how to access the default inbox folder and do some manipulating o’ the emails.
Friend Sub EnumerateInboxEmails() Dim inbox As Outlook.Folder = Nothing Dim ns As Outlook._NameSpace = OutlookApp.Session inbox = ns.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox) Dim mailItems As Outlook.Items = inbox.Items For i As Integer = 1 To mailItems.Count Dim outlookItem As Object = mailItems(i) Dim mailItem As Outlook._MailItem = _ TryCast(outlookItem, Outlook._MailItem If mailItem IsNot Nothing Then Console.WriteLine(mailItem.Subject) End If 'Release COM Objects! Marshal.ReleaseComObject(outlookItem) Next 'Release COM Objects! If mailItems IsNot Nothing Then Marshal.ReleaseComObject(mailItems) If ns IsNot Nothing Then Marshal.ReleaseComObject(ns) If inbox IsNot Nothing Then Marshal.ReleaseComObject(inbox) End Sub
It all begins by grabbing the default inbox folder. Next we grab the items within the inbox and loop through them. Granted, this is where the sample gets a bit lame but I bet you have some ideas that could make this exciting. Something like looping through all the emails and saving them to a CSV file? I don’t know… it’s up to you.
The last bit, I release all the COM objects I created. This is a best practice for all Office add-in development, not just for when you work with emails.
How to create and send a mail item
Creating an email with code is easy. Writing a coherent and grammatically correct email via code is not. That is something best left to users. Here, I have two samples. The first shows how to create an email and display it.
Friend Sub CreateMailItem() Dim email As Outlook._MailItem email = OutlookApp.CreateItem(Outlook.OlItemType.olMailItem) email.Subject = "My Automated Email" email.Display(True) 'Release! If email IsNot Nothing Then Marshal.ReleaseComObject(email) End Sub
The idea is you automate the creation of an email, automate it a bit by inserting a subject line, then display it so the use can finalize it and send it.
But what if you want to automate it and send it… the user be damned? They’ll probably mess it up anyway with grammatical errors. In this scenario, you want to borrow heavily from this sample code:
Friend Sub CreateAndSendEmail(recipientName As String) Dim email As Outlook._MailItem Dim recipients As Outlook.Recipients Dim recipient As Outlook.Recipient email = OutlookApp.CreateItem(Outlook.OlItemType.olMailItem) email.Subject = "Another automated email" email.Body = "Hi there...want to order take out for lunch?" recipients = email.Recipients recipient = recipients.Add(recipientName) recipient.Type = Outlook.OlMailRecipientType.olTo recipient.Resolve() If recipient.Resolved Then email.Send() Else MessageBox.Show("You do not have an email address for " & recipientName & ".", _ "Recipient not found", MessageBoxButtons.OK, MessageBoxIcon.Information) End If 'Release them COM Objects! If Not IsNothing(recipients) Then Marshal.ReleaseComObject(recipients) If Not IsNothing(recipient) Then Marshal.ReleaseComObject(recipient) If Not IsNothing(email) Then Marshal.ReleaseComObject(email) End Sub
What we do here is:
- create the email
- fill some important properties like Subject, Body, and Recipients
- resolve the recipient email address
- send the sucker!
Of course, we also clean up after ourselves too. Mom would be proud… if she knew anything about Outlook development that is.
How to delete/remove a mail item
The only thing more fun than creating stuff is destroying it. It can be cathartic. Out with the old, in with the new, etc. Here, in the following sample, you will see how to delete a single email item that resides in either an Outlook Explorer or Inspector window.
Friend Sub DeleteMailItem(ByVal InspectorOrExplorer As Object) Dim mailItem As Outlook._MailItem = Nothing Dim selection As Outlook.Selection = Nothing Dim item As Object = Nothing If TypeOf InspectorOrExplorer Is Outlook._Explorer Then Try 'Explorer.Selection fires an exception for a top-level folder selection = CType(InspectorOrExplorer, Outlook._Explorer).Selection item = selection.Item(1) If TypeOf item Is Outlook._MailItem Then mailItem = CType(item, Outlook._MailItem) mailItem.Delete() End If Marshal.ReleaseComObject(item) Catch Finally If selection IsNot Nothing Then Marshal.ReleaseComObject(selection) End Try ElseIf TypeOf InspectorOrExplorer Is Outlook._Inspector Then Try item = CType(InspectorOrExplorer, Outlook._Inspector).CurrentItem mailItem = TryCast(item, Outlook._MailItem) If mailItem IsNot Nothing Then mailItem.Delete() End If Marshal.ReleaseComObject(item) Catch End Try End If End Sub
Microsoft made it tricky by giving Outlook two types of windows… but I like it. It’s a challenge. In the sample above, you see the Selection object. This object contains the mail item currently selected by the user. We check the type of window and branch accordingly.
For Explorers, the code grabs first selected item. If the user selected more than one mail item… too bad… we only delete one today. For Inspectors, we don’t use the Selection object. We use the Inspector’s CurrentItem property to get to the MailItem. We then delete it.
Okay, deleting one email is fine-and-dandy. But sometimes I like to delete everything… especially after vacation. This sample doesn’t delete everything. Instead, it deletes all emails residing in the active folder that have a low priority.
Friend Sub DeleteMailItems(matchCriteria As String) 'Lets assume the current folder of the Explorer 'Examples of MatchCriteria could be...... '[Importance] = low '[DateReceived] = today() '[UnRead] = true 'etc. Dim explorer As Outlook._Explorer Dim folder As Outlook.Folder Dim folderItems As Outlook.Items Dim filteredItems As Outlook.Items explorer = OutlookApp.ActiveExplorer folder = explorer.CurrentFolder If folder.DefaultItemType = Outlook.OlItemType.olMailItem Then folderItems = folder.Items filteredItems = folderItems.Restrict(matchCriteria) For i As Integer = 1 To filteredItems.Count Dim outlookItem As Object = filteredItems(i) Dim mail As Outlook._MailItem mail = TryCast(outlookItem, Outlook._MailItem) If mail IsNot Nothing Then mail.Delete() End If 'Release COM Objects! Marshal.ReleaseComObject(outlookItem) Next 'Relaese COM Objects! Marshal.ReleaseComObject(filteredItems) Marshal.ReleaseComObject(folderItems) End If 'Release COM Objects! Marshal.ReleaseComObject(folder) Marshal.ReleaseComObject(explorer) End Sub
The code grabs a reference to the ActiveExplorer‘s folder object and ensures we are dealing with emails. Then, we use the Restrict method to filter based off of a search string (I included samples in the code). Then, the code rummages around via a Loop and removes them.
How to attach files to an email
If you automate Outlook emails, you will, at some point, want to attach a file to the email. All you need to do is grab the email and add an attachment to its Attachments collection.
Friend Sub AttachFileToEmail(mailItem As Outlook._MailItem, filePath As String) Dim attachments As Outlook.Attachments attachments = mailItem.Attachments attachments.Add(filePath, Outlook.OlAttachmentType.olByValue) Marshal.ReleaseComObject(attachments) End Sub
You will, of course, need to know the file path for the file you want to attach.
How to save and delete all attachments in the inbox
Sometimes, you have 100s or 1000s of emails in a folder. These emails will have attachments that take up space. Here is a code sample that will clear some space by saving the attachments to a Windows folder and removing them from Outlook.
Friend Sub SaveAllAttachmentsInInbox(savePath As String) Dim ns As Outlook._NameSpace = Nothing Dim inbox As Outlook.Folder = Nothing ns = OutlookApp.Session inbox = ns.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox) Dim mailItems As Outlook.Items Dim attachmentItems As Outlook.Items mailItems = inbox.Items attachmentItems = mailItems.Restrict("[HasAttachment] = True") For i As Integer = 1 To attachmentItems.Count Dim outlookItem As Object = attachmentItems(i) Dim mailItem As Outlook._MailItem mailItem = TryCast(outlookItem, Outlook._MailItem) If mailItem IsNot Nothing Them Dim attachments As Outlook.Attachments = mailItem.Attachments While attachments.Count > 0 Dim attach As Outlook.Attachment = Nothing attach = attachments(1) attach.SaveAsFile(savePath & "\" & attach.FileName) attach.Delete() Marshal.ReleaseComObject(attach) End While Marshal.ReleaseComObject(attachments) mailItem.Save() End If Marshal.ReleaseComObject(outlookItem) Next 'Release the COM Marshal.ReleaseComObject(attachmentItems) Marshal.ReleaseComObject(mailItems) Marshal.ReleaseComObject(ns) Marshal.ReleaseComObject(inbox) End Sub
Once again, I use the Restrict method to filter items before I process them. This strategy saves a few cycles. After I have a collection of mail items with attachments, I save each attachment to a file path and delete them from their parent email. Lastly, and this is important, I call MailItem’s Save method. If I don’t do that, the attachment will remain in Outlook.
Useful events
We have a few articles already that cover how to work with Outlook Item events. I’ll refer you to them if you want to dig deeper. Here, I want to point a few Outlook events that might prove useful when coding against Outlook emails.
To use these events, you need to add an ADXOutlookEvents object to the AddinModule.
NewMail and NewMailEx
These two events are similar for various reasons:
a) their names
b) what they do
c) their usefulness
Both occur when Outlook receives email.
NewMail executes when one or more new mail items hit the Outlook inbox. It’s a real stinker in terms of usefulness because it doesn’t tell you which items arrived… just that some items arrived. It’s a lot like when one of my kids calls my name and then forgets what they were going to tell me.
NewMailEx also occurs when one more mail items hit the inbox. But, this even provides us with a comma-delimited string. This string contains the EntryIDs of all items received since the last time NewMailEx executed. It’s obvious you want to ignore NewMail and utilize NewMailEx…
Private Sub adxOutlookEvents_NewMailEx(sender As Object, _ entryIDCollection As String) Handles adxOutlookEvents.NewMailEx Dim ns As Outlook._NameSpace = Nothing Dim mailItem As Outlook._MailItem = Nothing Dim entryIDs As String() Try ns = OutlookApp.Session entryIDs = entryIDCollection.Split(",") For i = 0 To entryIDs.Length - 1 Dim outlookItem As Object outlookItem = ns.GetItemFromID(entryIDs(i)) mailItem = TryCast(outlookItem, Outlook._MailItem) If mailItem IsNot Nothing Then mailItem.Display() End If Marshal.ReleaseComObject(outlookItem) Next Marshal.ReleaseComObject(ns) Catch End Try End Sub
This code sample takes the comma-delimited string, splits it, and loops through its values. It then calls the GetItemFromID function that is found in the Session object (which is actually an Outlook Namespace object… ugh). GetItemFromID retrieves the mail item and then the code opens it. If there are lots of emails, this will annoy the user… a sure sign you have developed a solid Outlook add-in.
ItemSend
Anytime the user sends an email is a great time to mess with it. I’ve been tempted to write and install Outlook add-ins on my friends’ PCs that help them with their email sending. I have not succumbed to this temptation and have instead opted for productive things like the code sample below.
Private Sub adxOutlookEvents_ItemSend(sender As Object, _ e As ADXOlItemSendEventArgs) Handles adxOutlookEvents.ItemSend Dim mailItem As Outlook._MailItem mailItem = TryCast(e.Item, Outlook._MailItem) If mailItem IsNot Nothing Then mailItem.Body = "I LOVE YOU!!!" mailItem.Save() End If End Sub
The trick here is to use ADXOlItemSendEventArgs object (e) to get to the mail item that is “sending”. Then, you make someone’s day by changing the Body of the email. Just think through how this strategy could be used to make the world a better place.
For more information about this event, please see How to handle the Outlook ItemSend event: C# and VB.NET examples.
***
I think this is an appropriate place to end this discussion of working with Outlook emails. These samples will get you started. After you master them, you can keep reading our technical blog as well as our forums to learn more.
Available downloads:
This sample Outlook add-in was developed using Add-in Express for Office and .net:
Outlook Mail Items example (VB.NET)
Outlook 2013 add-in development in Visual Studio 2012 for beginners
- Part 1: Working with Outlook Application & base objects
- Part 2: Creating custom Outlook views
- Part 3: Creating custom Outlook forms
- Part 4: Outlook UI – Explorer and Inspector Windows. What is customizable?
- Part 5: Customizing Outlook main menu, context menus and Backstage view
- Part 6: Creating custom Outlook ribbons and toolbars
- Part 7: Advanced view regions for Outlook 2013 – 2003
- Part 8: Advanced form regions for Outlook 2013 – 2003
- Part 9: Working with Outlook Accounts, Stores, Folders and Items
11 Comments
Under NewMailEx – the “..word of caution” alludes that Outlook rules are executed prior to the event itself. Can you please confirm that or advise if this is a result of add-in express or the Outlook event itself? From what I understand, the event fires prior to any other actions in outlook, including rules..
Thanks.
Hi Mesfin,
You are right, the NewMailEx event fires when an item is still in the Inbox folder, before a rule is processed. We have removed “A word of caution” paragraph from the post. Thank you for pointing this out!
Hi there
This would have been a lovely example, but it does not work in VS 2010…
Any chance you have a working sample for VS 2010?
Thanks
–Mark
Hi Mark,
Thank you for pointing us to the issue. I have just modified the sample project, please download the updated version.
I have VS.NET 2005, I want to handle the MailItem Save/SaveAs event, How can i capture it?
I have used mailitem write event, But it does not work.
Hi Amit,
You can use the Write event of the MailItem object for such task. This event occurs when a mail item is saved, either explicitly (for example, using the Save or SaveAs methods) or implicitly (for example, in response to a prompt when closing the item’s inspector).
Also, you can use ADXRibbonCommand component (with IdMso=FileSaveAs) to intercept clicking on the Save As ribbon button.
Hi,
I want C# code for delete all mail items from outlook\\Inbox\\Test(My FOlder).
My code is below
for (int k = 1; k <= Attach.Count; k++)
{
Attachitem = (Microsoft.Office.Interop.Outlook.Attachment)Attach[k];
Attachitem.SaveAsFile(downloadPath + Attachitem.FileName);
Console.WriteLine(Attachitem.FileName + " is saved");
mail.Delete();
}
by using above code : example i am having 4 mail items in my outlook folder while coming to the above loop downloading and deleting only 2 mails.
FOR OTHER ITEMS I NEED TO RUN MY CODE AGAIN AND AGAIN.
Request you to help in this one.
Hello Ravi,
You need to loop through the folder items in the reverse order: for (int k = Attach.Count; k >= 1; k–)
Super Working fine Anderi..
for (int k = Attach.Count; k >= 1; –k)
One minor nitpick – when you add an attachment in the `AttachFileToEmail()` example, the result is simply ignored even though it is a COM object reference by itself and should thus be explicitly releases as well. Otherwise we’re leaving releasing that Attachment COM object reference up to the .NET GC.
Hello Jurko,
You are correct! Thank you!