ItemsEvents_ItemAddEventHandler does not always fire on incoming mails

  • Thread starter Thread starter thomas.schager
  • Start date Start date
T

thomas.schager

Hi,

I use the following code to detect new incoming emails in the inbox:

Outlook.MAPIFolder oMapiFolder =
this.Application.Session.GetDefaultFolder( Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderInbox );

oMapiFolder.Items.ItemAdd += new
Microsoft.Office.Interop.Outlook.ItemsEvents_ItemAddEventHandler( EmailHandler.HandleEmail );

Now i regognized, that the event does not fire sometimes, especially
when the inbox is active.
Is there a common solution for this issue?



Thanks,
Thomas
 
Most MAPI based events such as ItemAdd won't fire if more than 15 items come
in at once. In those cases the only event that fires is the Extended MAPI
level folder_changed event. Even with NewMailEx you run the risk of missing
items, although that event does handle more than 15 items.

What most of us do if we need to monitor a folder like that is to run a
sweep for unprocessed items at a timer interval to supplement the ItemAdd
event handler.
 
You must keep the COM object that raises events referenced at all times. In
your case you do not have a global/class variable to hold the Items
collection, as soon as GC releases it, no events will be fired:

Outlook.Items m_Items = null; //class member
....
Outlook.MAPIFolder oMapiFolder =
this.Application.Session.GetDefaultFolder(
Microsoft.Office.Interop.Outlook.OlDefaultFolders.olFolderInbox );
m_Items = oMapiFolder.Items;
m_Items.ItemAdd += new
Microsoft.Office.Interop.Outlook.ItemsEvents_ItemAddEventHandler(
EmailHandler.HandleEmail );


Dmitry Streblechenko (MVP)
http://www.dimastr.com/
OutlookSpy - Outlook, CDO
and MAPI Developer Tool
 
You must keep the COM object that raises events referenced at all times. In
your case you do not have a global/class variable to hold the Items
collection, as soon as GC releases it, no events will be fired:

Thanks a lot, keeping the right things in memory enables a stable
recognition
of emails. Obviously, also a lot more than 15 new incoming emails
seems to
be no problem for the firing Outlook 2007 component.

Anyhow, I added a button to parse unread messages. With
inBoxItems.Restrict("[Unread] = true"), I can filter unread messages.

How can I exclude messages with Outlook 2007's "Red Category"?
inBoxItems.Restrict("[Unread] = true And Not([Categories] = 'Red
Category')")
and others do not work, I get an COM Exception.


Thanks,
Thomas.
 
Restrict cannot be used with the Categories property.
Below is the help topic for the Restrict method from Outlook VBA help file:

Restrict Method
See AlsoApplies ToExampleSpecifics
Applies a filter to the Items collection, returning a new collection
containing all of the items from the original that match the filter. This
method is an alternative to using the Find method or FindNext method to
iterate over specific items within a collection. The Find or FindNext
methods are faster than filtering if there are a small number of items. The
Restrict method is significantly faster if there is a large number of items
in the collection, especially if only a few items in a large collection are
expected to be found.

Note If you are using user-defined fields as part of a Find or Restrict
clause, the user-defined fields must exist in the folder. Otherwise the code
will generate an error stating that the field is unknown. You can add a
field to a folder by displaying the Field Chooser and clicking New.

expression.Restrict(Filter)

expression Required. An expression that returns an Items object.

Filter Required String. A filter string expression to be applied. For
details, see the Find method.

Remarks
This method cannot be used and will cause an error with the following
properties:

Body
Categories

Children

Class

Companies

CompanyLastFirstNoSpace

CompanyLastFirstSpaceOnly

ContactNames

Contacts

ConversationIndex

DLName

Email1EntryID

Email2EntryID

Email3EntryID

EntryID

HTMLBody

IsOnlineMeeting

LastFirstAndSuffix

LastFirstNoSpace

AutoResolvedWinner

BodyFormat

InternetCodePage

Permission
LastFirstNoSpaceCompany
LastFirstSpaceOnly

LastFirstSpaceOnlyCompany

LastFirstNoSpaceAndSuffix

MemberCount

NetMeetingAlias

NetMeetingAutoStart

NetMeetingOrganizerAlias

NetMeetingServer

NetMeetingType

RecurrenceState

ReplyRecipients

ReceivedByEntryID

RecevedOnBehalfOfEntryID

ResponseState

Saved

Sent

Submitted

VotingOptions

DownloadState

IsConflict

MeetingWorkspaceURL


Creating Filters for the Find and Restrict Methods
The syntax for the filter varies depending on the type of field you are
filtering on.

String (for Text fields)

When searching Text fields, you can use either an apostrophe ('), or double
quotation marks (""), to delimit the values that are part of the filter. For
example, all of the following lines function correctly when the field is of
type String:

sFilter = "[CompanyName] = 'Microsoft'"

sFilter = "[CompanyName] = ""Microsoft"""

sFilter = "[CompanyName] = " & Chr(34) & "Microsoft" & Chr(34)

Note If the search string contains a single quote character, escape the
single quote character in the string with another single quote character.
For example,

sFilter = "[Subject] = 'Can''t'"

Similarly, if the search string contains a double quote character, escape
the double quote character in the string with another double quote
character.

Date

Although dates and times are typically stored with a Date format, the Find
and Restrict methods require that the date and time be converted to a string
representation. To make sure that the date is formatted as Microsoft Outlook
expects, use the Format function. The following example creates a filter to
find all contacts that have been modified after January 15, 1999 at 3:30
P.M.

sFilter = "[LastModificationTime] > '" & Format("1/15/99 3:30pm", "ddddd
h:nn AMPM") & "'"

Boolean Operators

Boolean operators, TRUE/FALSE, YES/NO, ON/OFF, and so on, should not be
converted to a string. For example, to determine whether journaling is
enabled for contacts, you can use this filter:

sFilter = "[Journal] = True"

Note If you use quotation marks as delimiters with Boolean fields, then an
empty string will find items whose fields are False and all non-empty
strings will find items whose fields are True.

Keywords (or Categories)

The Categories field is of type keywords, which is designed to hold multiple
values. When accessing it programmatically, the Categories field behaves
like a Text field, and the string must match exactly. Values in the text
string are separated by a comma and a space. This typically means that you
cannot use the Find and Restrict methods on a keywords field if it contains
more than one value. For example, if you have one contact in the Business
category and one contact in the Business and Social categories, you cannot
easily use the Find and Restrict methods to retrieve all items that are in
the Business category. Instead, you can loop through all contacts in the
folder and use the Instr function to test whether the string "Business" is
contained within the entire keywords field.

Note A possible exception is if you limit the Categories field to two, or a
low number of values. Then you can use the Find and Restrict methods with
the OR logical operator to retrieve all Business contacts. For example (in
pseudocode): "Business" OR "Business, Personal" OR "Personal, Business."
Category strings are not case sensitive.

Integer

You can search for Integer fields with, or without quotation marks as
delimiters. The following filters will find contacts that were created using
Outlook 2000:

sFilter = "[OutlookInternalVersion] = 92711"

sFilter = "[OutlookInternalVersion] = '92711'"

Using Variables as Part of the Filter

As the Restrict method example illustrates, you can use values from
variables as part of the filter. The following Microsoft Visual Basic
Scripting Edition (VBScript) code sample illustrates syntax that uses
variables as part of the filter.

sFullName = "Dan Wilson"

' This approach uses Chr(34) to delimit the value.

sFilter = "[FullName] = " & Chr(34) & sFullName & Chr(34)

' This approach uses double quotation marks to delimit the value.

sFilter = "[FullName] = """ & sFullName & """"

Using Logical Operators as Part of the Filter

Logical operators that are allowed are AND, OR, and NOT. The following are
variations of the clause for the Restrict method so you can specify multiple
criteria.

OR: The following code returns all contact items that have either Business
or Personal as their category.

sFilter = "[Categories] = 'Personal' Or [Categories] = 'Business'"

AND: The following code retrieves all personal contacts who work at
Microsoft.

sFilter = "[Categories] = 'Personal' And [CompanyName] = 'Microsoft'"

NOT: The following code retrieves all personal contacts who don't work at
Microsoft.

sFilter = "[Categories] = 'Personal' And Not([CompanyName] = 'Microsoft')"

Additional Notes

If you are trying to use the Find or Restrict methods with user-defined
fields, the fields must be defined in the folder, otherwise an error will
occur. There is no way to perform a "contains" operation. For example, you
cannot use Find or Restrict to search for items that have a particular word
in the Subject field. Instead, you can use the AdvancedSearch method, or you
can loop through all of the items in the folder and use the InStr function
to perform a search within a field. You can use the Find and Restrict
methods to search for items that begin within a certain range of characters.
For example, to search for all contacts with a last name beginning with the
letter M, use this filter:

sFilter = "[LastName] > 'LZZZ' And [LastName] < 'N'"

Example
This Visual Basic for Applications (VBA) example uses the Restrict method to
get all Inbox items of Business category and moves them to the Business
folder. To run this example, create or make sure a subfolder called
'Business' exists under Inbox.

Sub MoveItems()
Dim myOlApp As Outlook.Application
Dim myNamespace As Outlook.NameSpace
Dim myFolder As Outlook.MAPIFolder
Dim myItems As Outlook.Items
Dim myRestrictItems As Outlook.Items
Dim myItem As Outlook.MailItem
Set myOlApp = CreateObject("Outlook.Application")
Set myNamespace = myOlApp.GetNamespace("MAPI")
Set myFolder = _
myNamespace.GetDefaultFolder(olFolderInbox)
Set myItems = myFolder.Items
Set myRestrictItems = myItems.Restrict("[Categories] = 'Business'")
For i = myRestrictItems.Count To 1 Step -1
myRestrictItems(i).Move myFolder.Folders("Business")
Next
End Sub
If you use VBScript in an Outlook form, you do not create the Application
object, and you cannot use named constants. This example shows how to
perform the same task using VBScript.

Sub CommandButton1_Click()
Set myNameSpace = Application.GetNameSpace("MAPI")
Set myFolder = myNameSpace.GetDefaultFolder(6)
Set myItems = myFolder.Items
Set myRestrictItems = myItems.Restrict _ ("[Categories] = 'Business'")
For i = myRestrictItems.Count To 1 Step -1
myRestrictItems(i).Move myFolder.Folders("Business")
Next
End Sub
This Visual Basic for Applications example uses the Restrict method to
apply a filter to contact items based on the item's LastModificationTime
property.

Public Sub ContactDateCheck()
Dim myOlApp As Outlook.Application
Dim myNamespace As Outlook.NameSpace
Dim myContacts As Outlook.Items
Dim myItems As Outlook.Items
Dim myItem As Object
Set myOlApp = CreateObject("Outlook.Application")
Set myNamespace = myOlApp.GetNamespace("MAPI")
Set myContacts = myNamespace.GetDefaultFolder(olFolderContacts).Items
Set myItems = myContacts.Restrict("[LastModificationTime] >
'01/1/2003'")
For Each myItem In myItems
If (myItem.Class = olContact) Then
MsgBox myItem.FullName & ": " & myItem.LastModificationTime
End If
Next
End Sub

The following Visual Basic for Applications example is the same as the
example above, except that it demonstrates the use of a variable in the
filter.

Public Sub ContactDateCheck2()
Dim myOlApp As Outlook.Application
Dim myNamespace As Outlook.NameSpace
Dim myContacts As Outlook.Items
Dim myItem As Outlook.Object
Dim DateStart As Date
Dim DateToCheck As String
Dim myRestrictItems As Outlook.Items
Set myOlApp = CreateObject("Outlook.Application")
Set myNameSpace = myOlApp.GetNamespace("MAPI")
Set myContacts = myNameSpace.GetDefaultFolder(olFolderContacts).Items
DateStart = #01/1/2003#
DateToCheck = "[LastModificationTime] >= """ & DateStart & """"
Set myRestrictItems = myContacts.Restrict(DateToCheck)
For Each myItem In myRestrictItems
If (myItem.Class = olContact) Then
MsgBox myItem.FullName & ": " & myItem.LastModificationTime
End If
Next
End Sub


Dmitry Streblechenko (MVP)
http://www.dimastr.com/
OutlookSpy - Outlook, CDO
and MAPI Developer Tool

You must keep the COM object that raises events referenced at all times.
In
your case you do not have a global/class variable to hold the Items
collection, as soon as GC releases it, no events will be fired:

Thanks a lot, keeping the right things in memory enables a stable
recognition
of emails. Obviously, also a lot more than 15 new incoming emails
seems to
be no problem for the firing Outlook 2007 component.

Anyhow, I added a button to parse unread messages. With
inBoxItems.Restrict("[Unread] = true"), I can filter unread messages.

How can I exclude messages with Outlook 2007's "Red Category"?
inBoxItems.Restrict("[Unread] = true And Not([Categories] = 'Red
Category')")
and others do not work, I get an COM Exception.


Thanks,
Thomas.
 
Back
Top