Searching Outlook email (and replying to it) using Excel VBA - vba

I want to search ALL my outlook for latest message in a conversation (I use Subject name as search key).
This latest message can be in Inbox, Sent Items, in a sub folder of Inbox, a sub-sub folder of Inbox (anywhere).
I can achieve this by some very tedious code, going through every level of each major folder, but not only this method is very messy, I can't determine if this found message is the latest in this conversation.
I have the following code, which
--> Searches Inbox for "searchKey"
--> If finds it in Inbox folder, replies to it
--> If not, it moves into subfolders of Inbox, and continues the same process
Dim olApp As Outlook.Application
Dim olNs As Namespace
Dim Fldr As MAPIFolder
Dim olFldr As MAPIFolder
Dim olMail ' As Outlook.MailItem
Dim i As Integer
Set olApp = New Outlook.Application
Set olNs = olApp.GetNamespace("MAPI")
Set Fldr = olNs.GetDefaultFolder(olFolderInbox)
Set olFldr = Fldr
tryAgain:
For Each olMail In olFldr.Items
If InStr(olMail.Subject, searchKey) <> 0 Then
Set ReplyAll = olMail.ReplyAll
With ReplyAll
.HTMLBody = Msg & .HTMLBody
emailReady = True
.Display
End With
End If
Next olMail
If Not emailReady Then
i = i + 1
If i > Fldr.Folders.Count Then
MsgBox ("The email with the given subject line was not found!")
Exit Sub
Else
Set olFldr = Fldr.Folders(i)
GoTo tryAgain
End If
End If
This code might be confusing and long, so please let me know if you need any clarification.
The question is: How can I search through ALL Outlook, without going manually through every folder/subfolder/sub-subfolder... without this method, and find the LAST message in a specific conversation? Or, at least, how can I optimize this code so I don't miss any folder, and know the dates and times these emails were sent?

You can use the built in AdvancedSearch function, which returns a Search object containing items.
These should have date properties, so you only need your code to go through the search object mailItems and find that with the latest date ( ReceivedTime)?
I would suggest using the bottom example on that page - it gets a table object from the search, and then you use
Set MyTable = MySearch.GetTable
Do Until MyTable.EndOfTable
Set nextRow = MyTable.GetNextRow()
Debug.Print nextRow("ReceivedTime")
Loop
From there, you can do the comparison to find the latest time, and if you want to do something with the mailitem you would need to obtain the "EntryID" column from the table.
Then use the GetItemFromID method of the NameSpace object to obtain a full item, since the table returns readonly objects.
You can also apply a date filter to the search if you wish, if you knew a minimum date for instance.

To go through all folders do this:
Go once through all the primary folders in Outlook and then for each major folder go through each subfolder. If you have more branches then is guess you have to add more levels to the code "for each Folder3 in folder2.folders". Also in the if clause you can test the date of the mail and go from the newest to the oldest. Set oMsg.display to see what mail is being checked
Public Sub FORWARD_Mail_STAT_IN()
Dim Session As Outlook.NameSpace
Dim oOutLookObject As New Outlook.Application
Dim olNameSpace As NameSpace
Dim oItem As Object
Dim oMsg As Object
Dim searchkey As String
Set oOutLookObject = CreateObject("Outlook.Application")
Set oItem = oOutLookObject.CreateItem(0)
Set olNameSpace = oOutLookObject.GetNamespace("MAPI")
Set Session = Application.Session
Set Folders = Session.Folders
For Each Folder In Folders 'main folders in Outlook
xxx = Folder.Name
For Each Folder2 In Folder.Folders 'all the subfolders from a main folder
yyy = Folder2.Name
Set oFolder = olNameSpace.Folders(xxx).Folders(yyy) 'in each folder we search all the emails
For Z = oFolder.Items.Count To 1 Step -1 ' For Z = 1 To oFolder.Items.Count
With oFolder.Items(Z)
Set oMsg = oFolder.Items(Z)
If Format(oMsg.SentOn, "mm/dd/yyyy") = Format(Date, "mm/dd/yyyy") And InStr(1, LCase(oMsg.Subject), searchkey, vbTextCompare) > 0 Then
oMsg.display
' insert code
End If
End With
Next Z
Next Folder2
Next Folder

Related

Is there a way to compare all the titles of all Rss feeds and delete duplicates? [duplicate]

This question already has answers here:
How can I compare all the titles of all RSS feeds and delete duplicates?
(2 answers)
Closed 5 years ago.
I'm wondering if there is a way to compare ALL TITLES in ALL RSS FEEDS and delete the duplicates.
I read through a lot of RSS Feeds, and it's obvious that a lot of people cross-post to several forums, and then I end up seeing the same RSS Feed multiple times.
I really just want to see each one one single time. Is there a way to list all feeds, and delete duplicates, if I actually have duplicates in my entire MS Outlook RSS Feed list?
Here's 0m3r's script, modified slightly.
Option Explicit
Public Sub Example()
Dim olNs As Outlook.NameSpace
Dim RSS_Folder As Outlook.MAPIFolder
Dim Item As Object
Dim Items As Items
Dim DupItem As Object
Dim i As Long
Dim j As Long
For j = 1 To 21
Set olNs = Application.GetNamespace("MAPI")
Set RSS_Folder = olNs.GetDefaultFolder(olFolderRssFeeds).Folders(j)
Set DupItem = CreateObject("Scripting.Dictionary")
Set Items = RSS_Folder.Items
For i = Items.Count To 1 Step -1
DoEvents
If TypeOf Items(i) Is PostItem Then
Set Item = Items(i)
If DupItem.Exists(Item.Subject) Then
Debug.Print Item.Subject ' Print on Immediate Window
Debug.Print TypeName(Item) ' Print on Immediate Window
Item.Delete
Else
'Debug.Print Item.Subject
DupItem.Add Item.Subject, 0
End If
End If
Next i
Debug.Print RSS_Folder
Next j
Set olNs = Nothing
Set RSS_Folder = Nothing
Set Item = Nothing
Set Items = Nothing
Set DupItem = Nothing
End Sub
Iterating over all items in the folder is not really a good idea.
For Each myItem In subFolder.Items
If InStr(myItem.Subject, "[on hold]") > 0 Then
You can use the Find/FindNext or Restrict methods of the Items class to find all items that correspond to your conditions. Read more about them in the following articles:
How To: Use Find and FindNext methods to retrieve Outlook mail items from a folder (C#, VB.NET)
How To: Use Restrict method to retrieve Outlook mail items from a folder
Also you may find the AdvancedSearch method of the Application class helpful.
The key benefits of using the AdvancedSearch method in Outlook are:
The search is performed in another thread. You don’t need to run another thread manually since the AdvancedSearch method runs it automatically in the background.
Possibility to search for any item types: mail, appointment, calendar, notes etc. in any location, i.e. beyond the scope of a certain folder. The Restrict and Find/FindNext methods can be applied to a particular Items collection (see the Items property of the Folder class in Outlook).
Full support for DASL queries (custom properties can be used for searching too). You can read more about this in the Filtering article in MSDN. To improve the search performance, Instant Search keywords can be used if Instant Search is enabled for the store (see the IsInstantSearchEnabled property of the Store class).
Finally, you can stop the search process at any moment using the Stop method of the Search class.
Read more about that in the Advanced search in Outlook programmatically: C#, VB.NET article.
Work with Dictionary Object to compare Items.Subject in your olFolderRssFeeds
Dictionary in VBA is a collection-object:
you can store all kinds of things in it: numbers, texts, dates, arrays, ranges, variables and objects, Every item in a Dictionary gets its own unique key and
With that key you can get direct access to the item (reading/writing).
Here is quick Example code
Option Explicit
Public Sub Example()
Dim olNs As Outlook.NameSpace
Dim RSS_Folder As Outlook.MAPIFolder
Dim Item As Object
Dim Items As Items
Dim DupItem As Object
Dim i As Long
Set olNs = Application.GetNamespace("MAPI")
Set RSS_Folder = olNs.GetDefaultFolder(olFolderRssFeeds) _
.Folders("Microsoft At Home")
Set DupItem = CreateObject("Scripting.Dictionary")
Set Items = RSS_Folder.Items
For i = Items.Count To 1 Step -1
DoEvents
If TypeOf Items(i) Is PostItem Then
Set Item = Items(i)
If DupItem.Exists(Item.subject) Then
Debug.Print Item.subject ' Print on Immediate Window
Debug.Print TypeName(Item) ' Print on Immediate Window
' Item.Delete
Else
DupItem.Add Item.subject, 0
End If
End If
Next i
Set olNs = Nothing
Set RSS_Folder = Nothing
Set Item = Nothing
Set Items = Nothing
Set DupItem = Nothing
End Sub
This Example shows how to process all Folders under RSS Feed Folders
Option Explicit
Public Sub DupeRSS()
Dim olNs As Outlook.NameSpace
Dim RSS_Folder As Outlook.MAPIFolder
Set olNs = Application.GetNamespace("MAPI")
Set RSS_Folder = olNs.GetDefaultFolder(olFolderRssFeeds)
' // Process Current Folder
Example RSS_Folder
End Sub
Public Sub Example(ByVal ParentFolder As Outlook.MAPIFolder)
Dim Folder As Outlook.MAPIFolder
Dim Item As Object
Dim DupItem As Object
Dim Items As Items
Dim i As Long
Set DupItem = CreateObject("Scripting.Dictionary")
Set Items = ParentFolder.Items
For i = Items.Count To 1 Step -1
DoEvents
If TypeOf Items(i) Is PostItem Then
Set Item = Items(i)
If DupItem.Exists(Item.subject) Then
Debug.Print Item.subject ' Print on Immediate Window
Debug.Print TypeName(Item) ' Print on Immediate Window
Item.Delete
Else
DupItem.Add Item.subject, 0
End If
End If
Next i
' // Recurse through subfolders
If ParentFolder.Folders.Count > 0 Then
For Each Folder In ParentFolder.Folders
Example Folder
Debug.Print Folder.Name
Next
End If
Set Folder = Nothing
Set Item = Nothing
Set Items = Nothing
Set DupItem = Nothing
End Sub
Remember the code will only compare duplicate in single folder

search for emails with specific subject title IF UNREAD and save attachments into folder

I am using the following vba code which should search for all emails with a specific subject title i.e. with the subject 'test'
Then only if the email is unread then save the attachment from that email into a folder.
There may be one or several emails with the subject test so I want all the unread emails with the subject test to have their attachments saved to the folder.
Here is my code:
Sub Work_with_Outlook()
Set olApp = CreateObject("Outlook.Application")
Dim olNs As Outlook.Namespace
Dim Fldr As Outlook.MAPIFolder
Dim myItem As Object
Dim myAttachment As Outlook.Attachment
Dim I As Long
Dim olMail As Variant
Set olApp = New Outlook.Application
Set olNs = olApp.GetNamespace("MAPI")
Set Fldr = olNs.GetDefaultFolder(olFolderInbox)
Set myTasks = Fldr.Items
Set UnRead = myTasks.Restrict("[UnRead] = False")
Set olMail = myTasks.Find("[Subject] = ""test""")
If Not (olMail Is Nothing) And UnRead.Count = 0 Then
For Each myItem In myTasks
If myItem.Attachments.Count <> 0 Then
For Each myAttachment In myItem.Attachments
If InStr(myAttachment.DisplayName, ".txt") Then
I = I + 1
myAttachment.SaveAsFile "\\uksh000-file06\Purchasing\NS\Unactioned\" & myAttachment
End If
Next
End If
Next
For Each myItem In myTasks
myItem.UnRead = False
Next
MsgBox "Scan Complete."
Else
MsgBox "There Are No New Supplier Requests."
End If
End Sub
This does work to some degree, if I only have one email with the subject 'test' and it is unread then the script will get the attachment from that email and save it to my folder. However, if I have one email with the subject 'test' which is read and another email with the subject 'test' which is unread then the code won't work?
Please can someone show me where I am going wrong? Thanks in advance
It looks like you need to combine both comditions into a single one and use the Find/FindNext or Restrict methods to get an instance of the Items class which contains all items correspodning to your conditons. For example:
Set resultItems = myTasks.Restrict("[UnRead] = False AND [Subject] = ""test""")
See Enumerating, Searching, and Filtering Items in a Folder for information in MSDN.
Also you may find the sample code in the following articles:
How To: Use Find and FindNext methods to retrieve Outlook mail items from a folder (C#, VB.NET)
How To: Use Restrict method to retrieve Outlook mail items from a folder
How To: Get unread Outlook e-mail items from the Inbox folder
Advanced search in Outlook programmatically: C#, VB.NET

send all "visible" drafts with VBA in Outlook 2007

How do I automatically send out multiple (currently visible) draft items with VBA?
Please help, thank you.
Edit: It's a tough case, none of the items are in the drafts folder yet. These are generated emails that are on your screen, waiting to be sent.
Edit2: nvm, it's not going to help anyway. My script creates approximately 500 emails, and displaying the first 100 causes out of memory error. I opted to auto send them without displaying (it breaks the layout this way, but it's my only option for now.)
It just so happens that I ran into the same issue before and have code handy. If you're not already in Outlook, you will need to add a reference in the VBA IDE, Tools ---> References... and check the box next to "Microsoft Outlook 14.0 Object Library".
Dim oFolder As Folder
Dim oNS As NameSpace
Dim olMail As MailItem
If (MsgBox("Are you sure you want to send ALL EMAILS IN YOUR DRAFTS FOLDER?", vbYesNo + vbCritical, "WARNING: THIS WILL SEND ALL DRAFTS")) = vbYes Then
Set oNS = Outlook.Application.GetNamespace("MAPI")
Set oFolder = oNS.GetDefaultFolder(olFolderDrafts)
For i = 1 To oFolder.Items.Count
oFolder.Items(1).Send
Next
End If
Set oNS = Nothing
Here's some code. Replace Your Name in myFolders("Mailbox - Your Name") with your actual name as it appears in the mailbox.
Public Sub EmailOutlookDraftsMessages()
Dim lDraftItem As Long
Dim myOutlook As Outlook.Application
Dim myNameSpace As Outlook.NameSpace
Dim myFolders As Outlook.Folders
Dim myDraftsFolder As Outlook.MAPIFolder
'Send all items in the "Drafts" folder that have a "To" address filled in.
'Setup Outlook
Set myOutlook = Outlook.Application
Set myNameSpace = myOutlook.GetNamespace("MAPI")
Set myFolders = myNameSpace.Folders
'Set Draft Folder.
Set myDraftsFolder = myFolders("Mailbox - Your Name").Folders("Drafts")
'Loop through all Draft Items
For lDraftItem = myDraftsFolder.Items.Count To 1 Step -1
'Check for "To" address and only send if "To" is filled in.
If Len(Trim(myDraftsFolder.Items.Item(lDraftItem).To)) > 0 Then
'Send Item
myDraftsFolder.Items.Item(lDraftItem).Send
End If
Next lDraftItem
'Clean-up
Set myDraftsFolder = Nothing
Set myNameSpace = Nothing
Set myOutlook = Nothing
End Sub
Source Code adapted from this Question's answer.

RDO Session - loop through entire Inbox and move emails

Thanks to the excellent assistance given on this site I found the code below - which works perfectly. I cannot (embarrassingly enough) figure out how to loop through the entire Inbox to move all emails (rather than selection as the code below does).
Any assistance most gratefully appreciated it.
John
Sub MoveWithRecDate()
' Moves selected emails with correct dates maintained
Dim objNS As Outlook.NameSpace
Dim Session As Redemption.RDOSession
Dim objRDOFolder As Redemption.RDOFolder
Dim objItem As Outlook.MailItem
Dim objRDOMail As Redemption.RDOMail
Set objNS = Application.GetNamespace("MAPI")
Set Session = CreateObject("Redemption.RDOSession")
Session.Logon
Set inbox = Session.GetDefaultFolder(olFolderInbox)
Set objRDOFolder = inbox.Parent.Folders("Cabinet")
For Each objItem In Application.ActiveExplorer.Selection
Set objRDOMail = Session.GetMessageFromID(objItem.EntryID)
objRDOMail.Move objRDOFolder
Next
End Sub
I had not heard of Redemption before reading your question. It looks very interesting so thank you for the information; I will try it next time I need to write a new Outlook macro.
I assume from the lack of an answer to your question that few others use Redemption either.
The Redemption website implies that the structure of Redemption code will be almost identical to standard Outlook code. I can only recall once writing a macro which operated on user selected items but my recollection is that the code looked like yours. The code below is standard Outlook but I hope that is enough for you to create the equivalent Redemption code.
You macro has the comment ' Moves selected emails with correct dates maintained. This implies you think there is a method by which emails can be moved so that dates are not maintained. I do not know such a method.
The code below examines every item in the Inbox. I did not want to move everything out of my Inbox so I have skipped items that are not mail items and are not from a specific sender.
I hope this is enough to get you going.
Sub MoveWithRecDate()
Dim FolderDest As MAPIFolder
Dim ItemToBeMoved As Boolean
Dim ItemCrnt As Object
Dim FolderSrc As MAPIFolder
Set FolderSrc = CreateObject("Outlook.Application"). _
GetNamespace("MAPI").GetDefaultFolder(olFolderInbox)
Set FolderDest = FolderSrc.Parent.Folders("Cabinet")
For Each ItemCrnt In FolderSrc.Items
ItemToBeMoved = True ' Assume item to be moved until discover otherwise
With ItemCrnt
If .Class = olMail Then
If .SenderEmailAddress <> "noreply#which.co.uk" Then
' Mail item not from Which
ItemToBeMoved = False
End If
Else
' Not mail item so do not move
ItemToBeMoved = False
End If
If ItemToBeMoved Then
.Move FolderDest
End If
End With
Next
End Sub

How to send multiple drafts from Outlook 2003

Outlook wont let me send multiple drafts at the same time. Is there an easy way to send multiple drafts at once in outlook? without having to open each one individually?
From what i've read, seen and tried; this is not possible from within outlook itself, and thus a programming solution would be required, probably some VB script
ok, i found a bit of VB that does it:
`Public Sub SendDrafts()
Dim lDraftItem As Long
Dim myOutlook As Outlook.Application
Dim myNameSpace As Outlook.NameSpace
Dim myFolders As Outlook.Folders
Dim myDraftsFolder As Outlook.MAPIFolder
'Send all items in the "Drafts" folder that have a "To" address filled
'in.
'Setup Outlook
Set myOutlook = Outlook.Application
Set myNameSpace = myOutlook.GetNamespace("MAPI")
Set myFolders = myNameSpace.Folders
'Set Draft Folder. This will need modification based on where it's
'being run.
Set myDraftsFolder = myFolders("$MAILBOX").Folders("$DRAFTS")
'Loop through all Draft Items
For lDraftItem = myDraftsFolder.Items.Count To 1 Step -1
'Check for "To" address and only send if "To" is filled in.
If Len(Trim(myDraftsFolder.Items.Item(lDraftItem).To)) > 0 Then
'Send Item
myDraftsFolder.Items.Item(lDraftItem).Send
End If
Next lDraftItem
'Clean-up
Set myDraftsFolder = Nothing
Set myNameSpace = Nothing
Set myOutlook = Nothing
End Sub
just replace $MAILBOX with your mailbox name and $DRAFTS with the name of your drafts folder.
This has been personnaly tested and seems to work fine.
Not very different from author's answer, but still:
Sub SendDrafts()
Dim ns As NameSpace
Dim drafts As MAPIFolder
Dim Item As MailItem
Set ns = Application.GetNamespace("MAPI")
Set drafts = ns.GetDefaultFolder(olFolderDrafts) ' 16
For Each Item In drafts.Items
'Item.Send
Next
End Sub
Please be careful as it really sends all emails in your default draft folder. After uncommenting the send line. Dim lines to allow for autocompletion when inside Outlook macro editor.
A useful version, which I just tested in Outlook 2000:
Drag the emails you wish to send to the Outbox. They won't be sent automatically, but using this version of the prior posting sends them:
Sub SendOutbox()
Dim ns As NameSpace
Dim outbox As MAPIFolder
Dim Item As MailItem
Set ns = Application.GetNamespace("MAPI")
Set outbox = ns.GetDefaultFolder(olFolderOutbox) ' 16
For Each Item In outbox.Items
Item.Send
Next
End Sub
That way, you can be selective.
Yes, you can write a macro or add-in to do that.