How to select IMAP acc in vba Outlook - vba

I have a problem, the macro below checks if there is a mail title from the sender. The problem is that in outlook, I have 2 accounts: IMAP and Exchange. Makro always chooses exchange. Where's the reason?
Sub srchmail()
Dim Itms As Items
Dim srchSender As String
Dim srchSubject As String
Dim strFilterBuild As String
Dim ItmsBuild As Items
Dim strFilter As String
Set olApp = Outlook.Application
Set objNS = olApp.GetNamespace("MAPI")
Set sub_olFolder = objNS.GetDefaultFolder(olFolderInbox)
Set sub_olFolder = sub_olFolder.Folders("SUBFOLDER")
Set Itms = sub_olFolder.Items
Dim i As Long
For i = 1 To Itms.Count
Next
srchSender = "SENDERMAIL"
srchSubject = "SUBJECTMAIL"
strFilter = "[SenderName] = '" & srchSender & "' And [Subject] = '" & srchSubject & "' And [SentOn] > '" & Format(Date, "dd-mm-yyyy") & "'"
Set Itms = Itms.Restrict(strFilter)
If Itms.Count = 0 Then
MsgBox "dont mail in " & sub_olFolder & " with sub:'" & srchSubject & "' on " & Format(Date, "dd-mm-yyyy")
Else
MsgBox "found mail in " & sub_olFolder & " with sub: '" & srchSubject & "' on " & Format(Date, "dd-mm-yyyy")
End If
ExitRoutine:
Set Itms = Nothing
End Sub

Your problem is:
Set sub_olFolder = objNS.GetDefaultFolder(olFolderInbox)
You can only have one default Inbox. Your default Inbox is clearly in the Exchange account. You will need to explicitly name the IMAP store to access its Inbox.
When you look at your folder pane, you will see something like this:
Xxxxxxxxxxx
Drafts
Deleted Items
Inbox
: :
Yyyyyyyyy
Drafts
Deleted Items
Inbox
SUBFOLDER
: :
Xxxxxxxxxxx and Yyyyyyyyy are the names of stores. Stores are the files in which Outlook saves all your emails, calendar items, tasks and so on. As I understand it, you MUST have one store per account. You can also have as many extra stores as you wish. I have stores named for my two accounts, “Archive”, “Test” and many more.
Try:
Set sub_olFolder = objNS.Folders("Yyyyyyyyy").Folders("Inbox")
Where “Yyyyyyyyy” is the name of the store (as it appears in the folder pane) containing the sub folder you wish to access.
I should perhaps add that I would have written:
Set Itms = Session.Folders("Yyyyyyyyy").Folders("Inbox").Folders("SUBFOLDER").Items
“Session” and “NameSpace” are supposed to be identical. I use Session because it avoids the need to create a namespace and because a long time ago I had a failure with NameSpace that I could not diagnose.
Unless you need to access the store or Inbox or SUBFOLDER in some other way, you do not need variables for them. Starting with the ultimate parent (Session) you can string the names of children, grandchildren and so on to any depth.
Be careful stringing properties together like this. (1) It can take a little time to get the string correct. (2) I have seen example of property strings where it is really difficult to determine what it being accessed. If you return to this macro in 12 months, will you remember what this string means? If someone else has to maintain your macro, will they understand what you have done? If in doubt, keep it simple.
Added because of error in original answer
It is not possible for me to test my answer. Try the following as a way for you to test my suggestion.
Replace "Yyyyyyyyy" in the following by the name of your IMAP store and then type it in your Immediate Window.
? Session.Folders("Yyyyyyyyy").Name
The interpreter should respond with the name of the IMAP store. If that works, try:
? Session.Folders("Yyyyyyyyy").Folders("Inbox").Name
The interpreter should respond Inbox. If that works, try:
? Session.Folders("Yyyyyyyyy").Folders("Inbox").Folders("SUBFOLDER").Name
The interpreter should respond SUBFOLDER. If that works, try:
? Session.Folders("Yyyyyyyyy").Folders("Inbox").Folders("SUBFOLDER").Items(1).ReceivedTime
The interpreter should respond with the date and time of the older email in the subfolder. If that works, my answer should work. If any of the above doesn't work, please respond with a detailed explanation of what failed

It looks like your Exchange account is set as default, so
when you get sub_olFolder, you are working with subfolder of Inbox of the message store that linked with Exchange account.

Related

Advanced Search Scope set to multiple mailboxes

I cannot find an example online of the syntax to do the advance search function in vba with the scope set to multiple mailboxes. Is there a way to do this or can you only search on a single mailbox and if you can what does the syntax look like? I have a scope variable setup like this.
Scope = "'" & OutApp.Session.Folders("sharemailbox#abc.com").FolderPath & "'"
However, i need to search on this mailbox and on othersharedmailbox#abc.com also so I was thinking maybe there is a way to do a union of two folders or something? Also, if there is a method as well to search all mailboxes in outlook as well because i may use that down the line as well. ANy help is appreciated as this is the last item to finishing my code!
You must run separate search processes for each store.
Using the Scope parameter, you can specify one or more folders in the same store, but you may not specify multiple folders in multiple stores. To specify multiple folders in the same store for the Scope parameter, use a comma character between each folder path and enclose each folder path in single quotes. For default folders such as Inbox or Sent Items, you can use the simple folder name instead of the full folder path. For example, the following two lines of code represent valid Scope parameters:
Scope = "'Inbox', 'Sent Items'"
or
Scope = "'" & Application.Session.GetDefaultFolder(olFolderInbox).FolderPath _
& "','" & Application.Session.GetDefaultFolder(olFolderSentMail).FolderPath & "'"
For example, a use-case may look like this:
Public blnSearchComp As Boolean
Private Sub Application_AdvancedSearchComplete(ByVal SearchObject As Search)
Debug.Print "The AdvancedSearchComplete Event fired"
If SearchObject.Tag = "Test" Then
m_SearchComplete = True
End If
End Sub
Sub TestAdvancedSearchComplete()
Dim sch As Outlook.Search
Dim rsts As Outlook.Results
Dim i As Integer
blnSearchComp = False
Const strF As String = "urn:schemas:mailheader:subject = 'Test'"
Const strS As String = "Inbox"
Set sch = Application.AdvancedSearch(strS, strF, "Test")
While blnSearchComp = False
DoEvents
Wend
Set rsts = sch.Results
For i = 1 To rsts.Count
Debug.Print rsts.Item(i).SenderName
Next
End Sub
Finally, you may find the Advanced search in Outlook programmatically: C#, VB.NET article helpful.

How to filter an Outlook view in VBA based on "To" email addresses

I have a view in Outlook that includes both "From" and "To" emails from a mailbox
I can very easily type in an email address into the Outlook search box, and the view will be instantly filtered to show all emails to and from the email address (plus perhaps, any other emails including this email address in the subject or body, but that's not an issue)
I would like to replicate this process via VBA - I have an Access DB with contact details, and would like to be able to simply filter this view based on a contact email address in the DB.
It seems like a very simple problem, but I can't find the solution. I have code that eg filters based on the from email address, but there seems no way to filter on a 'To' email address (I can filter on the 'To' display name but this is next to useless - it varies from one email to another, and seldom if ever contains the actual email address)
I have a DASL filter code that works to filter on the 'From' email addresses using DASL syntax as follows:
Const SchemaFrom As String = "urn:schemas:httpmail:fromemail"
Dim EM as string
EM = "myemail#me.com"
objView.Filter = Chr(34) & SchemaFrom & Chr(34) & " = '" & EM & "'"
But there is nothing similar for 'To' emails.
Ultimately I don't even need to filter based on eg the 'From' and 'To' email addresses - if there is a way to code this, so, like in the search box, it simply filters on any text field containing the email address that would be fine by me!!!
For example, is there a generic DASL search that will do this, so no need to eg dictate searching in eg fromemail?
All help much appreciated - it is so simple to do in the GUI of Outlook it must be possible from VBA surely?!
Should be
Dim Filter As String
Filter = "#SQL=" & Chr(34) & "urn:schemas:httpmail:fromemail" & _
Chr(34) & " Like '%0m3r 0m3r%'"
Or use
Filter = "[SenderEmailAddress] = '0m3r#email.com'"
Example
Option Explicit
Private Sub Examples()
Dim olNs As Outlook.NameSpace
Dim Inbox As Outlook.MAPIFolder
Dim Item As Outlook.MailItem
Dim Items As Outlook.Items
Dim msg As String
Set olNs = Application.GetNamespace("MAPI")
Set Inbox = olNs.GetDefaultFolder(olFolderInbox)
Dim Filter As String
Filter = "#SQL=" & Chr(34) & "urn:schemas:httpmail:fromemail" & _
Chr(34) & " Like '%0m3r 0m3r%'"
Set Items = Inbox.Items.Restrict(Filter)
msg = Items.Count & " Items in " & Inbox.Name
MsgBox (msg)
End Sub
MSDN fromemail Field | Microsoft Docs
Edit
for to. try
urn:schemas:httpmail:to
Or
urn:schemas:mailheader:to

How to uniquely identify an Outlook email as MailItem.EntryID changes when email is moved

My company uses a single email address for customers to send requests and orders to. we created an Access database that import emails into a table. The table creates it's own unique identifier for each email imported but is not supposed to import an email twice. The system was working as we were only concerned with emails coming into the inbox and didn't need anything more than that.
However we now need to know the "flow", "traffic" and "workload" of the email pool that this account is. The email that comes into the inbox is categorized and then moved to a folder called "my_tasks" and a subfolder the folder named as 1 of the four CSRs to be worked on by a manager. This email is then dealt with and the CSR moves it to a subfolder under another folder called "Completed".
So email comes into Inbox, gets moved to my_tasks\joeblow is dealt with and gets moved to Completed\Canada.
Currently I have code that iterates through the folders and finds each email, grabs the fields we want to store and then inserts them into the table. All of this is done in Access through VBA code.
Private Sub ImportEmailItem(objMailItem As Outlook.MailItem)
On Error GoTo ImportEmailItem_Error
' Set up DAO objects
Dim rstMB As DAO.Recordset
Dim dskippedFolderMailCount As Double
Dim strSQLrMB As String
strSQLrMB = "SELECT * FROM tblMailBox WHERE OLID='" & objMailItem.EntryID & "'"
Set rstMB = CurrentDb.OpenRecordset(strSQLrMB)
With rstMB
If Not .BOF And Not .EOF Then
.MoveLast
.MoveFirst
While (Not .EOF)
If .Updatable Then
.Edit
rstMB!Subject = objMailItem.Subject
rstMB!Body = objMailItem.Body
Call subCategory(objMailItem)
rstMB!CSR = IIf(Len(objMailItem.Categories) = 0, "Unassigned", objMailItem.Categories)
rstMB!Importance = objMailItem.Importance
rstMB!Region = objMailItem.Parent
rstMB!DateModified = objMailItem.LastModificationTime
rstMB!FlagCompleted = objMailItem.FlagRequest
rstMB!folder = objMailItem.Parent
rstMB!Path = objMailItem
.Update
End If
.MoveNext
Wend
Else
rstMB.AddNew
rstMB!olid = objMailItem.EntryID
rstMB!ConversationIndex = objMailItem.ConversationIndex
rstMB!ConversationID = objMailItem.ConversationID
rstMB!Conversation = objMailItem.ConversationTopic
rstMB!To = Left(objMailItem.To, 250)
rstMB!CC = Left(objMailItem.CC, 250)
rstMB!Subject = objMailItem.Subject
rstMB!Body = objMailItem.Body
Call subCategory(objMailItem)
rstMB!CSR = IIf(Len(objMailItem.Categories) = 0, "Unassigned", objMailItem.Categories)
rstMB!Importance = objMailItem.Importance
rstMB!From = objMailItem.SenderEmailAddress
rstMB!Region = objMailItem.Parent
rstMB!DateReceived = objMailItem.ReceivedTime
rstMB!DateSent = objMailItem.SentOn
rstMB!DateCreated = objMailItem.CreationTime
rstMB!DateModified = objMailItem.LastModificationTime
rstMB!FlagCompleted = objMailItem.FlagRequest
rstMB!folder = objMailItem.Parent
rstMB.Update
End If
.Close
End With
ImportEmailItem_Exit:
Set rstMB = Nothing
Exit Sub
ImportEmailItem_Error:
Debug.Print Err.Number & " " & Err.Description
Select Case Err.Number
Case 91
Resume Next
Case 3022
Resume Next
Case -2147221233
MsgBox "Customer Care Account Name is incorrect, please enter the Mail box name as seen in your outlook client.", vbOKOnly, "Mail Folder Name Error"
Me.txtMailAccountName.SetFocus
Exit Sub
Case Else
MsgBox "Error #: " & Err.Number & " " & Err.Description '& Chr(13) + Chr(10) & IIf(mail.Subject Is Null, "", mail.Subject) & " " & IIf(mail.ReceivedTime Is Null, "", mail.ReceivedTime)
' DoCmd.RunSQL "INSERT INTO tblImportReport(ImportDate,ImportFolder,ImportResult,ImportEmailCount) VALUES (#" & Now() & "#,'" & mailFolder & "', 'Error " & Err.Number & "', " & dMailCount & ")"
Resume Next 'cmdImportEmail_Exit
End Select
End Sub
Is there a way to uniquely identify an email with a single field no matter whether it has been moved or not?
I have an idea of what I could do to make sure I have the right email and get the original entry in my database. If there was no other way I could concatenate fields together to form a unique field and then get the database table's primary key field value.
You can use the PR_SEARCH_KEY property (DASL name http://schemas.microsoft.com/mapi/proptag/0x300B0102) - it does not change when a message is moved. It can be accessed through MailItem.PropertyAccessor.GetProperty, but unfortunately you cannot use PT_BINARY properties in Items.Find/Restrict.
You can also set your own named property using MailItem.UserProperties.
UPDATE:
For PR_SEARCH_KEY, see https://msdn.microsoft.com/en-us/library/office/cc815908.aspx.
MaillItem.UserProperties can be used from anywhere - Outlook Object Model is Outlook Object Model whether it is used from inside Outlook or externally from Excel. Keep in mind that setting a user property and saving the item will change its last modified date.
If you want to stick to PR_SEARCH_KEY, to be be able to sort on it, you might want to look at Redemption (I am its author) - its RDOFolder.Items.Find / Restrict methods allow PT_BINARY properties in its queries, e.g. "http://schemas.microsoft.com/mapi/proptag/0x300B0102" = '89F75D48972B384EB2C50266D1541099'
Here is VBA code tested in MS Access 2013 to extract the PR_SEARCH_KEY from an Outlook.MailItem and convert to a string:
Public Function strGetMailItemUniqueId( _
olMailItem As Outlook.MailItem _
) As String
Dim PR_SEARCH_KEY As String
PR_SEARCH_KEY = "http://schemas.microsoft.com/mapi/proptag/0x300B0102"
Dim olPA As Outlook.PropertyAccessor
Set olPA = olMailItem.PropertyAccessor
Dim vBinary As Variant
vBinary = olPA.GetProperty(PR_SEARCH_KEY)
strGetMailItemUniqueId = olPA.BinaryToString(vBinary)
End Function
In Microsoft Outlook versions like 2007, 2010, Office 365 etc. there is a property Message-ID in the headers section of the email.
You can use this property to uniquely identify an email.

Check if an email has NOT been received

I receive an email report twice every workday. Sometimes the machine that sends these reports crashes and no emails are sent out. What I am wanting to do is use some Outlook VBA to check if an email hasnt arrived at 12:15 and 17:05.
Finding an email that is there is fairly easy, but finding one that isnt is making me scratch my head a bit. I have a class module set up right now (I assume that would be the way to go) and have the code for what I want to do if no email has been received, but cannot figure out how to go about checking for the email at those times. It might be something simple, but have not really scripted in Outlook VBA before, so am not sure where to start.
The method pointed out in a comment.
Outlook VBA - Run a code every half an hour
Outlook VBA - Run a code every half an hour with outlook 2010 64 bits
A possibly simpler alternative. Set a recurring task with a reminder.
In ThisOutlookSession
Private Sub Application_Reminder(ByVal Item As Object)
If Item.Class = olTask Then
If InStr(Item.Subject, "subject") > 0 Then
ReminderUnreceivedMail
End If
End If
End Sub
Sub ReminderUnreceivedMail()
Dim Itms As Items
Dim srchSender As String
Dim srchSubject As String
Set Itms = GetNamespace("MAPI").GetDefaultFolder(olFolderInbox).Items
srchSender = "sender"
srchSubject = "subject"
Set Itms = Itms.Restrict("[SenderName] = 'sender' And [Subject] = 'subject' And [SentOn] > '" & Format(Date, "yyyy-mm-dd") & "'")
If Itms.count = 0 Then
MsgBox "No " & srchSubject & " email on " & Format(Date, "yyyy-mm-dd")
End If
Set Itms = Nothing
End Sub

Using the .Restrict method in Outlook VBA to filter on single recipient email address

I have code in Access that gets all emails in the user's Inbox that are sent by an individual email address. This code (simplified, below) works fine:
Dim outItems as Outlook.Items
Dim strEMAddress as string
Dim outFolder as Outlook.MAPIFolder
Set outFolder = outNS.GetDefaultFolder(olFolderInbox)
Set outItems = outFolder.Items
str="my#email.com"
Set outItems = outItems.Restrict("[SenderEmailAddress] = " & "'" & strEMAddress & "'")
I am looking for something that will do likewise on the SentMails folder, restricting the items to those sent to a specific email address.
I know this is complicated by the fact that .Recipients is a collection (as items can/do have more than one recipient). I am hoping there is a way to return a list of items that contain the email address I am looking for in any of the sent fields (To/CC/bcc - but happy with just To if this is easier).
I have searched online and found .To is no good (is not the email address) and I can't get pseudo code such as this work:
Set outItems = outItems.Restrict("[Recipients] = " & "'" & strEMAddress & "'")
You can use the DASL query as the filter string in your items.restrict method.
For example to find all mails i sent to Ali Raza i use the following
str_fltr = "#SQL=""urn:schemas:httpmail:displayto"" ci_phrasematch '%Ali Raza%'"
The good thing about the above DASL query is that it returns matches with multiple recepients whether if you use the jet syntax for searching resultx will only contain items with one recipient. Jet syntax is the one that you are currently using. You should use the [To] property rather than [Recipients]
Here https://msdn.microsoft.com/en-us/library/cc513841%28v=office.12%29.aspx#SearchingOutlookData_Overview is good place where you can learn almost everything about searching in outlook.
Here http://www.msoffice.us/Outlook/PDF/%28Outlook%202010%29%20Common%20DASL%20Property%20Tags.pdf is a list of common DASL tags which will come in handy if you get a grip on DASL syntax.
For multiple [TO/CC/BCC] filter example would be...
Option Explicit
Public Sub Example()
Dim olNs As Outlook.NameSpace
Dim Folder As Outlook.MAPIFolder
Dim Items As Outlook.Items
Dim Filter As String
Dim Msg As String
Dim i As Long
Set olNs = Application.GetNamespace("MAPI")
Set Folder = olNs.GetDefaultFolder(olFolderSentMail)
Filter = "#SQL=" & "urn:schemas:httpmail:displayto" & _
" Like '%John Doe%' Or " & _
"urn:schemas:httpmail:displaycc" & _
" Like '%John Doe%' Or " & _
"urn:schemas:httpmail:displaybcc" & _
" Like '%John Doe%'"
Set Items = Folder.Items.Restrict(Filter)
Msg = Items.Count & " Items in " & Folder.Name & " Folder"
If MsgBox(Msg, vbYesNo) = vbYes Then
For i = Items.Count To 1 Step -1
Debug.Print Items(i) 'Immediate Window
Next
End If
End Sub
now remember if the display name is John.Doe#Email.com then filter should be %John.Doe#Email.com% else use %John Doe%
If using Redemption is an option (I am its author), you can use RDOFolder.Items.Restrict - unlike Outlook Object Model, it does expand To/CC/BCC queries into recipient sub restrictions on PR_DISPLAY_NAME and PR_EMAIL_ADDRESS properties on each recipient (RES_SUBRESTRICTION / PR_MESSAGE_RECIPIENTS / RES_OR / PR_DISPLAY_NAME | PR_EMAIL_ADDRESS).
set Session = CreateObject("Redemption.RDOSession")
Session.MAPIOBJECT = Application.Session.MAPIOBJECT
set Folder = Session.GetFolderFromID(Application.ActiveExplorer.CurrentFolder.EntryID)
set restrItems = Folder.Items.Restrict(" TO = 'user#domain.demo' ")
You can also specify Recipients property in the SQL query - it will be matched against recipients of all types (to/cc/bb):
set restrItems = Folder.Items.Restrict(" Recipients = 'user#domain.demo' ")