Moving Emails in Outlook Folders to Subfolder with VBA? - excel

I have exported all subject of the emails from the main folder to excel spreadsheet in the first module of my project.
For the second module, or code. I would like to move the emails i extracted from the main folder to a sub-folder based on searching the email subject. I detailed the subfolder name, on a separate column of the spreadsheet.
Column 3 - The subject email
Column 8 - The subfolder name
Each email subject in the main folder is unique, So i used the "Find Method" then move the email to the subfolder. Since the list is dynamic every time i make an extract, i decided to use arrays, so that it can iterate when the list of email changes.
Example, the code has to place email in the main folder with subject "A" to folder "1".
Email subject Folder name
(Column 3) (Column 8)
A 1
B 1
C 2
D 2
E 1
Sub MovingEmails_Invoices()
'Declare your Variables
Dim i As Object
Dim items As Outlook.items
Dim subfolder As Outlook.Folder 'this will be the folder you want to move the Mail to
'Set Outlook Inbox Reference
Set OP = New Outlook.Application
Set NS = OP.GetNamespace("MAPI")
'To loop through subfolder and its folders
Set rootfol = NS.Folders("SYNTHES-JNJCZ-GBS.DE.AT.CH#ITS.JNJ.com")
Set Folder = rootfol.Folders("Austria")
'The list for invoice numbers and folders is dynamic
'Each subject being searched is different
Dim Listmails() As Variant
Dim Rowcount As Variant
Dim Mailsubject As Variant
Dim FolderName As Variant
Dim MS As Variant
'Establish the array based on the mailbox extract
Sheets("files").Activate
Listmails = Range("A2").CurrentRegion
'Ititerate through the array which is dynamic (One-dimensional)
For Rowcount = LBound(Listmails) To UBound(Listmails)
'3rd row for email subject
Mailsubject = Application.WorksheetFunction.Index(Listmails, Rowcount, 3)
MS = "[subject] = '" & Mailsubject & "'"
'Find the email based on the array for email subject
Set i = items
Set i = Folder.items.Find(MS)
If i.Class = olMail Then
'8th row for folder name
FolderName = Application.WorksheetFunction.Index(Listmails, Rowcount, 8)
Set subfolder = rootfol.Folders(FolderName)
'If email is found then mark it as read
item.UnRead = False
'Move it to the subfolder based on the array for folder name
i.Move subfolder
End If
Next Rowcount
End Sub
I had an error to conduct the below code, but i am not sure why
If i.Class = olMail Then
I am adding an improved code for the iteration part alone. i have error for
Set items = items.Restrict(MS)
'Ititerate through the array which is dynamic (One-dimensional)
For Rowcount = LBound(Listmails) To UBound(Listmails)
'3rd row for email subject 'used DASL Filter
Mailsubject = Application.WorksheetFunction.Index(Listmails, Rowcount, 3)
MS = "urn:schemas:mailheader:subject LIKE \'%" & Mailsubject & "%\'"
'Find the email based on the array for email subject
Set myitems = Folder.items
Set myrestrictitem = myitems.Restrict(MS)
For Each i In myrestrictitem
If TypeOf i Is Mailitem Then
'8th row for folder name
FolderName = Application.WorksheetFunction.Index(Listmails, Rowcount, 8)
Set subfolder = rootfol.Folders(FolderName)
'If email found then mark it as read
i.UnRead = False
'Move it to the subfolder based on the array for folder name
i.Move subfolder
Else
End If
Next
Next Rowcount
End Sub

I'm just looking at part of your code, but there's at least two big mistakes I spotted:
Why are you setting i twice? Also what is items?
Set i = items
Set i = Folder.items.Find(MS)
1: Do you perhaps want to check the TypeOf i?
If i.Class = olMail Then
2: What is item?
item.UnRead = False
Remove the line
Set i = items
Replace the line
If i.Class = olMail then
with
If TypeOf i Is MailItem Then
And replace item with i in the line item.UnRead = False

I'd suggest checking the subject line as a substring, for example:
dim filter as string = "urn:schemas:mailheader:subject LIKE \'%"+ wordInSubject +"%\'"
Also, you must use the FindNext in addition to the Find one or just the Restrict method:
Sub MovingEmails_Invoices()
'Declare your Variables
Dim i As Object
Dim items As Outlook.items
Dim subfolder As Outlook.Folder 'this will be the folder you want to move the Mail to
'Set Outlook Inbox Reference
Set OP = New Outlook.Application
Set NS = OP.GetNamespace("MAPI")
'To loop through subfolder and its folders
Set rootfol = NS.Folders("SYNTHES-JNJCZ-GBS.DE.AT.CH#ITS.JNJ.com")
Set Folder = rootfol.Folders("Austria")
'The list for invoice numbers and folders is dynamic
'Each subject being searched is different
Dim Listmails() As Variant
Dim Rowcount As Variant
Dim Mailsubject As Variant
Dim FolderName As Variant
Dim MS As Variant
'Establish the array based on the mailbox extract
Sheets("files").Activate
Listmails = Range("A2").CurrentRegion
'Ititerate through the array which is dynamic (One-dimensional)
For Rowcount = LBound(Listmails) To UBound(Listmails)
'3rd row for email subject
Mailsubject = Application.WorksheetFunction.Index(Listmails, Rowcount, 3)
MS = "urn:schemas:mailheader:subject LIKE \'%"& Mailsubject &"%\'"
'Find the email based on the array for email subject
Set items = Folder.Items
Set items = items.Restrict(MS)
i = resultItems.GetFirst()
While Not IsNothing(i)
If i.Class = olMail Then
'8th row for folder name
FolderName = Application.WorksheetFunction.Index(Listmails, Rowcount, 8)
Set subfolder = rootfol.Folders(FolderName)
'If email is found then mark it as read
i.UnRead = False
'Move it to the subfolder based on the array for folder name
i.Move subfolder
i = resultItems.GetNext()
End While
End If
Next Rowcount
End Sub
You can find the sample code and description 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

Related

Extract pdf files from an email from a specific contact (sender) and different inbox address in outlook

Good morning friends,
Please, I need your help, I have 2 problems:
1.- I wanted to be able to extract pdf files but an email from a specific contact (sender)
2.- I have several inboxes, how could I set another inbox, but not the one that comes by default - here I tried the following "Set Inbox = olNs.GetDefaultFolder (onothermail#gmail.com)" but it did not work for me
Thank you very much in advance
Option Explicit
Public Sub Example()
'// Declare your Variables
Dim olNs As Outlook.NameSpace
Dim Inbox As Outlook.MAPIFolder
Dim Items As Outlook.Items
Dim Item As Outlook.MailItem
Dim Atmt As Attachment
Dim Filter As String
Dim FilePath As String
Dim AtmtName As String
Dim i As Long
Dim objOwner As Outlook.Recipient
'// Set Inbox Reference
Set olNs = Application.GetNamespace("MAPI")
Set objOwner = olNs.CreateRecipient("secondMail#gmail.com")
Set Inbox = olNs.GetSharedDefaultFolder(objOwner)
FilePath = "C:\Users\Unity\Desktop\adjuntos\"
Filter = "[Unread] = True"
Set Items = Inbox.Items.Restrict(Filter)
'// Loop through backwards
For i = Items.Count To 1 Step -1
Set Item = Items(i)
DoEvents
If Item.Class = olMail Then
If Item.SenderEmailAddress = "senderx#gmail.com" Then
For Each Atmt In Item.Attachments
AtmtName = FilePath & Atmt.FileName
If ((InStr(Atmt.DisplayName, ".jpg") Or InStr(Atmt.DisplayName, ".zip") Or InStr(Atmt.DisplayName, ".PDF") Or InStr(Atmt.DisplayName, ".pdf"))) Then
Atmt.SaveAsFile FilePath & "\" & Atmt.DisplayName
End If
Item.UnRead = False
Next
End If
End If
Next
Set Inbox = Nothing
Set Items = Nothing
Set Item = Nothing
Set Atmt = Nothing
Set olNs = Nothing
End Sub
It seems additionally you need to check the sender's email address of the item. The MailItem.SenderEmailAddress property returns a string that represents the email address of the sender of the Outlook item.
Sub SetFlagIcon()
Dim mpfInbox As Outlook.Folder
Dim obj As Outlook.MailItem
Dim i As Integer
Set mpfInbox = Application.GetNamespace("MAPI").GetDefaultFolder(olFolderInbox).Folders("Test")
' Loop all items in the Inbox\Test Folder
For i = 1 To mpfInbox.Items.Count
If mpfInbox.Items(i).Class = olMail Then
Set obj = mpfInbox.Items.Item(i)
If obj.SenderEmailAddress = "someone#example.com" Then
'Set the yellow flag icon
obj.FlagIcon = olYellowFlagIcon
obj.Save
End If
End If
Next
End Sub
However, iterating over all items in the folder is not really a good idea. Use the Find/FindNext or Restrict methods of the Items class. Read more about these methods 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 use the AdvancedSearch method of the Application class helpful. See Advanced search in Outlook programmatically: C#, VB.NET for more information.
Use the Store.GetDefaultFolder method instead. It returns a Folder object that represents the default folder in the store and that is of the type specified by the FolderType argument. This method is similar to the GetDefaultFolder method of the NameSpace object. The difference is that this method gets the default folder on the delivery store that is associated with the account, whereas NameSpace.GetDefaultFolder returns the default folder on the default store for the current profile.

How to check if contact information exists in my Outlook contacts list?

I have code which adds contacts from a worksheet to my Outlook contacts. Each Contact is on a separate line and has 5 columns with First Name, Last name, Email Address, Company and Mobilephone Number.
How do I add only those lines from the worksheet, which aren't in my contacts, so it doesn't create duplicates?
Sub ExcelWorksheetDataAddToOutlookContacts3()
Dim oApplOutlook As Object
Dim oNsOutlook As Object
Dim oCFolder As Object
Dim oDelFolder As Object
Dim oCItem As Object
Dim oDelItems As Object
Dim lLastRow As Long, i As Long, n As Long, c As Long
'determine last data row in the worksheet:
lLastRow = Sheets("Sheet1").Cells(Rows.Count, "A").End(xlUp).Row
'Create a new instance of the Outlook application,
' if an existing Outlook object is not available.
'Set the Application object as follows:
On Error Resume Next
Set oApplOutlook = GetObject(, "Outlook.Application")
'if an instance of an existing Outlook object is not available,
' an error will occur (Err.Number = 0 means no error):
If Err.Number <> 0 Then
Set oApplOutlook = CreateObject("Outlook.Application")
End If
'disable error handling:
On Error GoTo 0
'use the GetNameSpace method to instantiate
' (ie. create an instance) a NameSpace object variable,
' to access existing Outlook items.
'Set the NameSpace object as follows:
Set oNsOutlook = oApplOutlook.GetNamespace("MAPI")
'----------------------------
'Empty the Deleted Items folder in Outlook so that
' when you quit the Outlook application you bypass the prompt:
' Are you sure you want to permanently delete all the items
' and subfolders in the "Deleted Items" folder?
'set the default Deleted Items folder:
'The numerical value of olFolderDeletedItems is 3.
'The following code has replaced the Outlook's built-in
' constant olFolderDeletedItems by its numerical value 3.
Set oDelFolder = oNsOutlook.GetDefaultFolder(3)
'set the items collection:
Set oDelItems = oDelFolder.Items
'determine number of items in the collection:
c = oDelItems.Count
'start deleting from the last item:
For n = c To 1 Step -1
oDelItems(n).Delete
Next n
'----------------------------
'set reference to the default Contact Items folder:
'The numerical value of olFolderContacts is 10.
'The following code has replaced the Outlook's built-in
' constant olFolderContacts by its numerical value 10.
Set oCFolder = oNsOutlook.GetDefaultFolder(10)
'post each row's data on a separate contact item form:
For i = 2 To lLastRow
'Using the Items.Add Method to create
' a new Outlook contact item in the default Contacts folder.
Set oCItem = oCFolder.Items.Add
'display the new contact item form:
oCItem.Display
'set properties of the new contact item:
With oCItem
.firstName = Sheets("Sheet1").Cells(i, 1)
.LastName = Sheets("Sheet1").Cells(i, 2)
.Email1Address = Sheets("Sheet1").Cells(i, 3)
.CompanyName = Sheets("Sheet1").Cells(i, 4)
.MobileTelephoneNumber = Sheets("Sheet1").Cells(i, 5)
End With
'close the new contact item form after saving:
'The numerical value of olSave is 0.
'The following code has replaced the Outlook's built-in
' constant olSave by its numerical value 0.
oCItem.Close 0
Next i
'quit the Oulook application:
oApplOutlook.Quit
'clear the variables:
Set oApplOutlook = Nothing
Set oNsOutlook = Nothing
Set oCFolder = Nothing
Set oDelFolder = Nothing
Set oCItem = Nothing
Set oDelItems = Nothing
MsgBox "Successfully Exported Worksheet Data to the Default Outlook Contacts Folder."
End Sub
Is this what you are trying? Here is a very basic fuction which uses Outlook Items.Find property to check if the email address exists in the address book.
Option Explicit
Dim OutApp As Object
Dim OutNs As Object
Dim OutFolder As Object
Dim OutItems As Object
Const olFolderContacts As Integer = 10
Sub Sample()
Set OutApp = CreateObject("Outlook.Application")
Set OutNs = OutApp.GetNameSpace("MAPI")
Set OutFolder = OutNs.GetDefaultFolder(olFolderContacts)
Set OutItems = OutFolder.items
Dim EmailToFind As String
'~~> Change email here
EmailToFind = "Sid#Sid.Com"
MsgBox DoesContactExists(EmailToFind)
End Sub
'~~> Function to check if the email exists
Private Function DoesContactExists(EmailAddress As String) As Boolean
Dim olContact As Object
On Error Resume Next
Set olContact = OutItems.Find("[Email1Address] = '" & name & "'")
On Error GoTo 0
If Not olContact Is Nothing Then DoesContactExists = True
End Function

How to extract the members' info of a distribution list, and save in Outlook contacts folder?

I have an Excel VBA macro (Macro A) to export the members' information (Name and Address) from Outlook contacts folder to Excel.
I am trying to retrieve the members of a distribution list, and push them into my Outlook contacts folder on a daily basis. In that case, I can use macro A to export the latest DL members found in my contacts folder.
My ultimate objective is to get the latest name and email address of the members found in a distribution list in Excel format.
I searched online for solutions that can directly export the members of Outlook distribution list to Excel, but didn't achieve my intended effect.
Sub PrintDistListDetails()
Dim olApplication As Object
Dim olNamespace As Object
Dim olContactFolder As Object
Dim olDistListItem As Object
Dim destWorksheet As Worksheet
Dim distListName As String
Dim memberCount As Long
Dim memberIndex As Long
Dim rowIndex As Long
Const olFolderContacts As Long = 10
distListName = "dl.xxxxxx" 'change the name accordingly
Set olApplication = CreateObject("Outlook.Application")
Set olNamespace = olApplication.GetNamespace("MAPI")
Set olContactFolder = olNamespace.GetDefaultFolder(olFolderContacts)
Set olDistListItem = olContactFolder.Items(distListName)
Set destWorksheet = Worksheets.Add
destWorksheet.Range("A1:B1").Value = Array("Name", "Address") 'column headers
memberCount = olDistListItem.memberCount
rowIndex = 2 'start the list at Row 2
'For memberIndex = 1 To memberCount
For memberIndex = 1 To 1
With olDistListItem.GetMember(memberIndex)
destWorksheet.Cells(rowIndex, "a").Value = .Name
destWorksheet.Cells(rowIndex, "b").Value = .Address
End With
rowIndex = rowIndex + 1
Next memberIndex
destWorksheet.Columns.AutoFit
Set olApplication = Nothing
Set olNamespace = Nothing
Set olContactFolder = Nothing
Set olDistListItem = Nothing
Set destWorksheet = Nothing
End Sub
It is only printing out the name of a distribution list, and its "parent email". For example, the output will be "dl.xxxxxx" in A2 cell, and "dl.xxxxxx#outlook.com" in B2 cell, instead of retrieving all the members in the distribution list.
How do I get the latest name and address of the members in a distribution list, and print in Excel using any of the two methods described above?
Your loop only runs once:
For memberIndex = 1 To 1
change it back to
For memberIndex = 1 To memberCount

Looping through Arrays with VBA, to Move outlook emails from one folder to another?

I want to move emails of invoices from a main folder to a different folder.
I extracted the subject of the emails with VBA from outlook in the first module, they are in column 3. Then I manually write out the folder I would like the emails to move to, in column 8. (The names of the folder is a subfolder)
Column 3 is the subject of the email which I extracted, I used the restrict method for outlook to return the email with the specific tittle
Column 8 is the folder I would like the email to move too.
Example is like below
The code has to place email in the main folder with subject'A' to Folder '1'
Column 3 columnn 8
A 1
B 2
C 2
D 1
E 1
The reason I use arrays is because, every time I make an extract, the list changes, hence it is dynamic. Therefore, I used LBound and UBound to include the whole list of invoices.
I have declared all variables here in the first module as 'public'. Only left the relevant ones here to the code
Sub MovingEmails_Invoices()
'Declare your Variables
Dim i As Object
Dim myitems As Object
Dim subfolder As Outlook.Folder
'Set Outlook Inbox Reference
Set OP = New Outlook.Application
Set NS = OP.GetNamespace("MAPI")
'To loop through subfolder and its folders
Set rootfol = NS.Folders("SYNTHES-JNJCZ-GBS.DE.AT.CH#ITS.JNJ.com")
Set Folder = rootfol.Folders("Austria")
'The list for invoice numbers and folders is dynamic
'Each subject being searched is different
Dim Listmails() As Variant
Dim Rowcount As Long
Dim Mailsubject As Variant
Dim FolderName As Variant
Dim MS As String
Dim myrestrictitem As Outlook.items
'Establish the array based on the mailbox extract
Sheets("files").Activate
Listmails = Range("A2").CurrentRegion
'Ititerate through the array which is dynamic (One-dimensional)
For Rowcount = LBound(Listmails) To UBound(Listmails)
'3rd row for email subject 'used DASL Filter
Mailsubject = Application.WorksheetFunction.Index(Listmails, Rowcount, 3)
MS = "urn:schemas:mailheader:subject LIKE \'%" & Mailsubject & "%\'"
'Find the email based on the array for email subject
Set myitems = Folder.items
Set myrestrictitem = myitems.Restrict(MS)
For each i in myrestrictitem
If i.class = olmail then
'8th row for folder name
FolderName = Application.WorksheetFunction.Index(Listmails, Rowcount,8)
Set subfolder = rootfol.Folders(FolderName) ' i have an error here
'If email found then mark it as read
i.UnRead = False
'Move it to the subfolder based on the array for folder name
i.Move subfolder
Next Rowcount
End Sub
Now, I used the example I got from Microsoft Office Center to construct the restrict part, the last example on this page: https://learn.microsoft.com/en-us/office/vba/api/outlook.items.restrict
when I try to do the same way, it doesn't work for my code.
The error message comes from;
Set myrestrictitem = myitems.Restrict(MS)
and
?
Set subfolder = rootfol.Folders(FolderName)
The error message is the condition is not correct. Also it could be because I am doing the loop incorrectly.
Could there be another way of doing this, without arrays maybe? do i need IF condition?
You condition must include the #SQL= prefix. It is also a good idea to double quote the DASL property names:
#SQL="urn:schemas:mailheader:subject" LIKE '%test%'
You also should not use "for each" when you are changing the collection (by calling Move). Use a down loop:
for i = myrestrictitem.Count to 1 step -1
set item = myrestrictitem.Item(i)
..
item.Move subfolder

Collate tables from outlook mails into an Excel sheet using Excel VBA

I have an Excel file which will be used as a tool collate tables from mails. One mail will have only one table and one record in it. I need to collate the records in all such tables (from different mails) into One Excel table. I have the following code to do it. This code when run, copies the entire text in body of mail to Excel (So the code works only if the mail has Table with no other text in the body of mail). But I need to copy only the Table present in the mail to Excel. Please help me modify the code to do this. Please note that I do not want to write any code in outlook. Also the copied table is pasted as text. I want them to get pasted in table format. The part of the code which will need modification is shown below.
Public Sub ExportToExcel1()
Application.ScreenUpdating = False
'Variable declaration
Dim i As Integer
Dim ns As Namespace
Dim Inbox As Outlook.MAPIFolder
Dim item As Object
Dim doClip As MSForms.DataObject
Dim d As String
'Set values for variables
i = 2
d = ActiveSheet.Range("subject").Value
Set ns = GetNamespace("MAPI")
Set Inbox = ns.GetDefaultFolder(olFolderInbox)
Set doClip = New MSForms.DataObject
'Loop to check mails and pull data
For Each item In Inbox.Items
If TypeName(item) = "MailItem" And item.Subject = d Then
doClip.SetText item.Body
doClip.PutInClipboard
ActiveSheet.Cells(1, 1).PasteSpecial "Text"
EndSub
There are two mistakes in your code:
You access item.Body which is the text body when you need the Html body.
You paste the entire body into the worksheet when you only want the table.
You need some extra variables:
Dim Html As String
Dim LcHtml As String
Dim PosEnd As Long
Dim PosStart As Long
Replace the If statement with:
If TypeName(item) = "MailItem" And item.Subject = d Then
Html = item.HTMLBody
LcHtml = LCase(Html)
PosStart = InStr(1, LcHtml, "<table")
If PosStart > 0 Then
PosEnd = InStr(PosStart, LcHtml, "</table>")
If PosEnd > 0 Then
Debug.Print "[" & Mid(Html, PosStart, PosEnd + 8 - PosStart) & "]"
doClip.SetText Mid(Html, PosStart, PosEnd + 8 - PosStart)
doClip.PutInClipboard
ActiveSheet.Cells(1, 1).PasteSpecial "Text"
End If
End If
End If

Resources