Outlook 2007 MailItem Info - Slow
I am trying to parse email in Outlook 2007. I need to get it organized as quickly as possible and seem to have some problems.
Mainly:
foreach( Folder fld in outllookApp.Session.Folders )
{
foreach( MailItem mailItem in fld )
{
string body = mailItem.Body;
}
}
and for 5000 emails, it takes over 100 seconds. It seems to me that it shouldn't be that long.
If I add:
string entry = mailItem.EntryID;
As a result, he gets an additional 30 seconds.
I do all sorts of string manipulations including regex on these strings and writing to the database, and yet these two strings take up 50% of my runtime.
I am using Visual Studio 2008
source to share
This kind of action will take a long time to complete as you have to pull data from the exchange store for each item.
I think you have a couple of options here.
Process this information out of range of CDO / RDO in some other process. Or Use MapiTables as this is the fastest way to get properties, there are caveats in this and you can do something in your process that can be tabled.
Ransom Wrap - http://www.dimastr.com/redemption/mapitable.htm
MAPI tables http://msdn.microsoft.com/en-us/library/cc842056.aspx
source to share
Are you just reading these lines in this loop, or are you reading a line, process it, and then move on to the next one? You can try to read all the messages in the HashTable inside your loop and then process them after they have been loaded - this might bring you some profit.
Any updates to the user interface are extremely expensive; if you are writing text or increasing the progress bar, it is best to do so sparingly.
source to share
We had the same problem even when the folders were local and there was no network lag.
We got a 10x speedup by storing a copy of each email in a local Sql Server CE table configured for the search we want. We also used refresh events to make sure the local database stays in sync with the Outlook / Exchange folders.
To completely eliminate user lag, we took the search from the Outlook stream and put it in its own stream. The perceived lag was worse than the actual lag.
source to share
I ran into a similar situation while trying to access Outlook mail via VBA (in Excel). However, in my case it was much slower: 1 email per second ! (Maybe it was slower in my case than in your case due to the fact that I implemented it in VBA).
Anyway I was able to improve the speed with SetColumnns (e.g. https://docs.microsoft.com/en-us/office/vba/api/Outlook.Items.SetColumns )
I know .. I know .. This only works for a few properties like "Subject" and "ReceivedTime", not body! But think again: do you really want to read all of your emails? or is it just a subset? maybe based on his "Subject" or "ReceivedTime" line? My requirement was to simply enter the body of the email if its subject matches a specific line!
Hence, I did below:
I added a second Outlook.Items object called myFilterItemCopyForBody and applied the same filter as the other Outlook.Items. So now I have two "Outlook.Items": "myFilterItem" and "myFilterItemCopyForBody" with the same email items because the same constraint conditions apply to both.
"myFilterItem" - for storing only the "Subject" and "ReceivedTime" properties of the corresponding letters (performed using SetColumns); "myFilterItemCopyForBody" - for storing all mail properties (including body).
Now both myFilterItem and myFilterItemCopyForBody are sorted using ReceivedTime so that they are in the same order.
After sorting, both loops are looped simultaneously in nested loops for each loop and select the corresponding properties (using a counter), as shown in the code below.
Dim myFilterItem As Outlook.Items
Dim myItems As Outlook.Items
Set myItems = olFldr.Items
Set myFilterItemCopyForBody = myItems.Restrict("@SQL=""urn:schemas:httpmail:datereceived"" > '" & startTime & "' AND ""urn:schemas:httpmail:datereceived"" < '" & endTime & "'")
Set myFilterItem = myItems.Restrict("@SQL=""urn:schemas:httpmail:datereceived"" > '" & startTime & "' AND ""urn:schemas:httpmail:datereceived"" < '" & endTime & "'")
myFilterItemCopyForBody.Sort ("ReceivedTime")
myFilterItem.Sort ("ReceivedTime")
myFilterItem.SetColumns ("Subject, ReceivedTime")
For Each myItem1 In myFilterItem
iCount = iCount + 1
For Each myItem2 In myFilterItemCopyForBody
jCount = jCount + 1
If iCount = jCount Then
'Display myItem2.Body if myItem1.Subject contain a specific string
'MsgBox myItem2.Body
jCount = 0
Exit For
End If
Next myItem2
Next myItem1
Note 1: Note that the Body property is accessible using myItem2 corresponding to myFilterItemCopyForBody.
Note 2: The fewer times the compiler loops to access the body property, the better! You can improve efficiency even further by playing with Restrict and logic to reduce the number of loops the compiler has to loop through the logic.
Hope this helps, although it's not new!
source to share