Outlook rule to move sent items with Excel VBA - excel

I have to sort about 8000 emails into the specific folders in Outlook (2013).
I created the folders in Outlook through an Excel list. This spreadsheet contains beside the foldername, as well the senders/receivers email address.
I want to create rules, following this example:
emails -> Received by sheet1.cells(i,4) -> move to folder =sheet1.cells(i,5)
Through googling I created this code:
Sub createOutlookRule()
Dim appOutlook As Outlook.Application
Dim olRules As Outlook.Rules
Dim myRule As Outlook.Rule
Dim moveToAction As Outlook.MoveOrCopyRuleAction
Dim fromAction As Outlook.ToOrFromRuleCondition
Dim myInbox As Outlook.Folder
Dim moveToFolder As Outlook.Folder
For i = 2 To 5
Set appOutlook = New Outlook.Application
Set myInbox = appOutlook.Session.GetDefaultFolder(olFolderInbox)
Set olRules = appOutlook.Session.DefaultStore.GetRules()
Set myRule = olRules.Create(Sheet2.Cells(i, 1), olRuleReceive)
Set fromAction = myRule.Conditions.From
a = Sheet2.Cells(i, 3)
Set moveToFolder = myInbox.Folders("Mifid").Folders(a)
With fromAction
.Enabled = True
If IsEmpty(Sheet2.Cells(i, 4)) Then GoTo 4 Else
.Recipients.Add (Sheet2.Cells(i, 4))
If IsEmpty(Sheet2.Cells(i, 5)) Then GoTo 3 Else
.Recipients.adds (Sheet2.Cells(i, 5))
3:
End With
Set moveToAction = myRule.Actions.moveToFolder
With moveToAction
.Enabled = True
.Folder = moveToFolder
End With
olRules.Save
4:
Next i
End Sub
This essentially creates the rule but so far does not move items.
I adjusted it for the sent-items but during the "move part" I get an error
Sub createOutlookRuleSENTITEMS()
Dim appOutlook As Outlook.Application
Dim olRules As Outlook.Rules
Dim myRule As Outlook.Rule
Dim moveToAction As Outlook.MoveOrCopyRuleAction
Dim SENTAction As Outlook.ToOrFromRuleCondition
Dim myInbox As Outlook.Folder
Dim moveToFolder As Outlook.Folder
For i = 2 To 5
Set appOutlook = New Outlook.Application
Set myInbox = appOutlook.Session.GetDefaultFolder(olFolderInbox)
Set olRules = appOutlook.Session.DefaultStore.GetRules()
Set myRuleSENT = olRules.Create(Sheet2.Cells(i, 1), olRuleSend)
Set TOAction = myRuleSENT.Conditions.SentTo
a = Sheet2.Cells(i, 3)
Set moveToFolder = myInbox.Folders("Mifid").Folders(a)
With TOAction
.Enabled = True
If IsEmpty(Sheet2.Cells(i, 4)) Then GoTo 4 Else
.Recipients.Add ("test#example.com")
If IsEmpty(Sheet2.Cells(i, 5)) Then GoTo 3 Else
.Recipients.adds (Sheet2.Cells(i, 5))
3:
End With
Set moveToAction = myRuleSENT.Actions.moveToFolder
With moveToAction
.Enabled = True
.Folder = moveToFolder
End With
olRules.Save
4:
Next i
End Sub
Error-Message:
Run-time error
Invalid operation. this rule action cannot be enabled because either the rule is read-only or invalid for the rule type, or the action conflicts with another action on the rule

The rules interface for sent items allows copy not move. (Does not prove it impossible.)
Option Explicit
Sub createOutlookRuleSENTITEMS()
' Reference Outlook nn.n Object Library
Dim appOutlook As Outlook.Application
Dim olRules As Outlook.Rules
Dim myRuleSENT As Outlook.Rule
Dim ToCondition As Outlook.ToOrFromRuleCondition
Dim CopySentItemRuleAction As Outlook.MoveOrCopyRuleAction
Dim myInbox As Outlook.Folder
Dim copyToFolder As Outlook.Folder
Dim i As Long
Set appOutlook = New Outlook.Application
Set myInbox = appOutlook.Session.GetDefaultFolder(olFolderInbox)
For i = 2 To 5
Set olRules = appOutlook.Session.DefaultStore.GetRules()
Debug.Print "Sheet2.Cells(i, 1): " & Sheet2.Cells(i, 1)
Set myRuleSENT = olRules.Create(Sheet2.Cells(i, 1), olRuleSend)
Set ToCondition = myRuleSENT.Conditions.SentTo
Dim a As String
a = Sheet2.Cells(i, 3)
Debug.Print "a: " & a
Set copyToFolder = myInbox.Folders("Mifid").Folders(a)
With ToCondition
.Enabled = True
Debug.Print "Sheet2.Cells(i, 4): " & Sheet2.Cells(i, 4)
If Not IsEmpty(Sheet2.Cells(i, 4)) Then
.Recipients.Add ("test#example.com")
If Not IsEmpty(Sheet2.Cells(i, 5)) Then
.Recipients.Add (Sheet2.Cells(i, 5))
End If
' The rules interface for sent items allows copy not move.
' (Does not prove it impossible.)
'
'Action is to copy, not move, the sent item
Dim oCopyTarget As Outlook.Folder
Set copyToFolder = myInbox.Folders("Mifid").Folders(a)
Set CopySentItemRuleAction = myRuleSENT.Actions.copyToFolder
With CopySentItemRuleAction
.Enabled = True
.Folder = copyToFolder
End With
olRules.Save
End If
End With
Next i
Debug.Print "Done."
End Sub

Related

How to create an Outlook calendar entry each time a workbook is saved?

I'd like to create an Outlook calendar meeting request each time a workbook is saved.
The meeting requests need to be added to a shared mailbox so that all users that have access see the meeting invite.
So far it adds an entry to my personal calendar.
Private Sub Workbook_AfterSave(ByVal Success As Boolean)
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("2021") 'define your sheet!
Dim olApp As Object 'create outlook application
Set olApp = CreateObject("Outlook.Application")
Dim olNS As Object 'get namespace
Set olNS = olApp.GetNamespace("MAPI")
'define constants if using late binding
Const olFolderCalendar As Long = 9
Const olAppointmentItem As Long = 1
Dim olRecItems As Object 'get all appointments
Set olRecItems = olNS.GetDefaultFolder(olFolderCalendar)
Dim strFilter As String 'filter for appointments
Dim olFilterRecItems As Object 'filtered appointments
Dim iRow As Long
iRow = 3
Do Until Trim$(ws.Cells(iRow, 3).Value) = vbNullString
'filter appointments for subject
strFilter = "[Subject] = '" & Trim$(ws.Cells(iRow, 4).Value) & "'"
Set olFilterRecItems = olRecItems.Items.Restrict(strFilter)
If olFilterRecItems.Count = 0 Then 'if subject does not exist
With olApp.CreateItem(olAppointmentItem)
.Subject = ws.Cells(iRow, 4).Value
.Start = ws.Cells(iRow, 3).Value
.AllDayEvent = True
.BusyStatus = 5
.ReminderSet = True
.Save
End With
ws.Cells(iRow, 3).Interior.ColorIndex = 50
End If
iRow = iRow + 1
Loop
End Sub
Update:
I managed to get this. The problem now is that it'll only create the calendar entry for the last line.
Private Sub Workbook_AfterSave(ByVal Success As Boolean)
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("2020") 'define your sheet!
Dim olApp As Object 'create outlook application
Set olApp = CreateObject("Outlook.Application")
Dim olNS As Object 'get namespace
Set olNS = olApp.GetNamespace("MAPI")
Dim olAppItem As Outlook.AppointmentItem
Dim myRequiredAttendee As Outlook.Recipient
'define constants if using late binding
Const olFolderCalendar As Long = 9
Const olAppointmentItem As Long = 1
Dim olRecItems As Object 'get all appointments
Set olRecItems = olNS.GetDefaultFolder(olFolderCalendar)
Set olAppItem = olRecItems.Items.Add(olAppointmentItem)
Dim strFilter As String 'filter for appointments
Dim olFilterRecItems As Object 'filtered appointments
Dim iRow As Long
iRow = 3
Do Until Trim$(ws.Cells(iRow, 3).Value) = vbNullString
'filter appointments for subject
strFilter = "[Subject] = '" & Trim$(ws.Cells(iRow, 4).Value) & "'"
Set olFilterRecItems = olRecItems.Items.Restrict(strFilter)
If olFilterRecItems.Count = 0 Then 'if subject does not exist
With olAppItem
Set myRequiredAttendee = .Recipients.Add("email address")
myRequiredAttendee.Type = olRequired
.MeetingStatus = olMeeting
.ReminderMinutesBeforeStart = 30
.Subject = ws.Cells(iRow, 4).Value
.Start = ws.Cells(iRow, 3).Value
.AllDayEvent = True
.BusyStatus = 5
.ReminderSet = True
.Send
End With
ws.Cells(iRow, 3).Interior.ColorIndex = 50
End If
iRow = iRow + 1
Loop
End Sub
Instead of the following code:
Dim olRecItems As Object 'get all appointments
Set olRecItems = olNS.GetDefaultFolder(olFolderCalendar)
You need to use the NameSpace.GetSharedDefaultFolder method which returns a Folder object that represents the specified default folder for the specified user. This method is used in a delegation scenario, where one user has delegated access to another user for one or more of their default folders (for example, their shared Calendar folder). For example:
Sub ResolveName()
Dim myNamespace As Outlook.NameSpace
Dim myRecipient As Outlook.Recipient
Dim CalendarFolder As Outlook.Folder
Set myNamespace = Application.GetNamespace("MAPI")
Set myRecipient = myNamespace.CreateRecipient("Eugene Astafiev")
myRecipient.Resolve
If myRecipient.Resolved Then
Call ShowCalendar(myNamespace, myRecipient)
End If
End Sub
Sub ShowCalendar(myNamespace, myRecipient)
Dim CalendarFolder As Outlook.Folder
Set CalendarFolder = myNamespace.GetSharedDefaultFolder(myRecipient, olFolderCalendar)
CalendarFolder.Display
End Sub

How to copy email info to Excel?

I have the following code to get email info from a specific sender. I cannot manage to copy the info to Excel.
I can see the info in the immediate window but nothing else.
Sub Getemaildetails()
Dim ol As Outlook.Application
Dim ns As Outlook.Namespace
Dim fol As Outlook.Folder
Dim i As Object
Dim mi As Outlook.MailItem
Dim Filtertext As String
Set ol = New Outlook.Application
Set ns = ol.GetNamespace("Mapi")
Set fol = ns.GetDefaultFolder(olFolderInbox)
Filtertext = "[SenderName]= 'Eskalem Bogale'"
Set i = fol.Items.Find(Filtertext)
Range("A2", Range("A2").End(xlDown).End(xlToRight)).Clear
If i Is Nothing Then
MsgBox "Nothing was found.", vbExclamation
Exit Sub
End If
If i.Class <> olMail Then
MsgBox "Item is not an email.", vbExclamation
Exit Sub
End If
Set mi = i
Debug.Print mi.Subject
End Sub
Since you do not try clarifying my clarification question, I only assumes that I correctly understood what you need. Meaning to return date from all received emails from that specific sender. It should be very fast, placing the data in an array and then dropping the processing result at once:
Sub GetEmaildetails()
Dim ol As Outlook.Application, ns As Outlook.NameSpace
Dim fol As Outlook.folder, i As Outlook.items, arrM
Dim mi As Outlook.MailItem, Filtertext As String, iEm As Long
Set ol = New Outlook.Application
Set ns = ol.GetNamespace("Mapi")
Set fol = ns.GetDefaultFolder(olFolderInbox)
Filtertext = "[SenderName]= 'Eskalem Bogale'"
'You can also use:
'Filtertext = "[From] = 'Eskalem Bogale'"
Set i = fol.items.Restrict(Filtertext)
Range("A2", Range("A2").End(xlDown).End(xlToRight)).Clear
If i Is Nothing Then
MsgBox "Nothing was found.", vbExclamation
Exit Sub
End If
ReDim arrM(1 To i.count + 1, 1 To 3)
iEm = 2
For Each mi In i
arrM(iEm, 1) = mi.Subject
arrM(iEm, 2) = mi.ReceivedTime
arrM(iEm, 3) = mi.size
iEm = iEm + 1
'it can also return Body, Catetories...
Next
Range("A2").Resize(UBound(arrM), 3).Value = arrM
MsgBox "Ready..."
End Sub

How to Convert my VBA process to run in MAC?

I have an excel macro that works perfect in windows (email text extraction), but when I run it in my mac it gives me the error missing the library Microsoft Outlook 16.0 Object Library.
I was thinking in late binding (I tried but I wasn't able to fix it)
Can you pls help me to fix my code in order to run it in my mac? thanks in advance.
Code Below:
Sub DetailExtraction() 'MacVersion
On Error GoTo ErrHandler
Application.ScreenUpdating = False
' SET Outlook APPLICATION OBJECT.
Dim objOutlook As Object
Set objOutlook = CreateObject("Outlook.Application")
' CREATE AND SET A NameSpace OBJECT.
Dim objNSpace As Object
' THE GetNameSpace() METHOD WILL REPRESENT A SPECIFIED NAMESPACE.
Set objNSpace = objOutlook.GetNamespace("MAPI")
' CREATE A FOLDER OBJECT.
Dim myFolder As Object
Set myFolder = objNSpace.GetDefaultFolder(olFolderInbox)
Dim Item As Object
Dim iRows, iCols As Integer
iRows = 2
' LOOP THROUGH EACH ITEMS IN THE FOLDER.
'For Each objItem In myFolder.Items
' LOOP THROUGH EACH ITEMS IN THE SELECTION.
For Each objItem In ActiveExplorer.Selection
If objItem.Class = olMail Then
Dim objMail As Outlook.MailItem ' PROBLEM IS IN THIS LINE
Set objMail = objItem
Cells(iRows, 1) = objMail.SenderEmailAddress
Cells(iRows, 2) = objMail.To
Cells(iRows, 3) = objMail.Subject
Cells(iRows, 4) = objMail.ReceivedTime
Cells(iRows, 6) = objMail.Body
Cells(iRows, 6).WrapText = False
'MsgBox Prompt:=objMail.Body
End If
'WRAP UP FILE OFF
' Cells*i.WrapText = False
' SHOW OTHER PROPERTIES, IF YOU WISH.
'Cells(iRows, 6) = objMail.Body
'Cells(iRows, 5) = objMail.CC
'Cells(iRows, 6) = objMail.BCC
'Cells(iRows, 4) = objMail.Recipients(1)
iRows = iRows + 1
Next
Set objMail = Nothing
' RELEASE.
Set objOutlook = Nothing
Set objNSpace = Nothing
Set myFolder = Nothing
ErrHandler:
Debug.Print Err.Description
Application.ScreenUpdating = True
MsgBox "Environments Details Extracted from the Selected Emails (" & iRows - 2 & ")"
End Sub

Move a specific number of emails from shared Outlook folder

Every few days I manually move a specified number of emails from a shared network mailbox to subfolders of team managers. They want them moved from oldest to newest. Both the managers and the number can change each time.
I wrote a script for moving a small number of emails with a specific subject line in the folder to a subfolder to be worked by a certain group.
I have tried to adapt this to my current task.
Sub Moverdaily()
On Error GoTo errHandler
Dim olApp As Outlook.Application
Dim objNS As Outlook.Namespace
Dim olFolder As Outlook.MAPIFolder
Dim msg As Outlook.MailItem
Dim manager= As Outlook.MAPIFolder
Dim cell,start,finish,rng As Range
Dim countE,countM As Integer
Dim emcount, casecount, movedcount
Set rng = Range(Range("A2"), Range("A2").End(xlDown))
Set olApp = Outlook.Application
Set objNS = olApp.GetNamespace("MAPI")
Set olFolder = objNS.Folders("Documents").Folders("Inbox")
Set manager = objNS.Folders("Document").Folders("Inbox").Folders("Manager")
Set finish = ThisWorkbook.Sheets("Mover").Range("I11")
Set start = ThisWorkbook.Sheets("Mover").Range("I10")
start.Value = Format(Now, "hh:mm:ss")
Set emcount = Range("I12")
Set casecount = Range("I13")
Set movedcount = Range("I14")
countM = 0
countE = 0
For i = olFolder.Items.count To 1 Step -1
For Each cell In rng
If (cell.Text = (onlyDigits(msg.Subject))) Then
msg.move manager
countM = 1 + countM
cell.Offset(0, 1).Value = "Moved"
End If
Next
countE = 1 + countE
Next
finish.Value = Format(Now, "hh:mm:ss")
emcount.Value = countE
casecount.Value = rng.count
movedcount.Value = countM
errHandler:
MsgBox ("Error " & Err.Number & ": " & Err.Description)
Exit Sub
End Sub
Firstly, do not use "for each" with a collection that you change - MailItem.Mpve removes an itemn from that collection. Use a for i = Items.Count to 1 step -1 instead.
Secondly, do not loop through all item - if you already know the entry ids (rngarry), simply call Namespace.GetItemfromID.

Excel VBA Code to retrieve e-mails from outlook

I am to write a VBA code that would retrive emails from Outlook based on certain conditions. The problem I have is that I have to denote a certain folder in my code (in the example below the folder denoted is "PRE Costumer". I would like to retrive all emails from my 'inbox' or in better case from all outlook folders. The problem is that my inbox consists of many subfolders (because of rules0. My problem is that I may not know all the subfolders names (as many useres are going to use the macro and even someone can have the e mails in Personal Folders).
Could you please advise is there a way to overcome this problem?
Please let me know if this question is vague (as I am newcomer)
Please find the line that I have probelm with marked with a comment.
Sub GetFromInbox()
Dim olApp As Outlook.Application
Dim olNs As Namespace
Dim Fldr As MAPIFolder
Dim olMail As Variant
Dim i As Integer
Set olApp = New Outlook.Application
Set olNs = olApp.GetNamespace("MAPI")
'Below is the line I have problem with
Set Fldr = olNs.GetDefaultFolder(olFolderInbox).Folders("PRE Customer")
i = 1
x = Date
For Each olMail In Fldr.Items
If InStr(olMail.Subject, "transactions") > 0 _
And InStr(olMail.ReceivedTime, x) > 0 Then
ActiveSheet.Cells(i, 1).Value = olMail.Subject
ActiveSheet.Cells(i, 2).Value = olMail.ReceivedTime
ActiveSheet.Cells(i, 3).Value = olMail.SenderName
i = i + 1
End If
Next olMail
Set Fldr = Nothing
Set olNs = Nothing
Set olApp = Nothing
End Sub
Just loop through all the folders in Inbox.
Something like this would work.
Edit1: This will avoid blank rows.
Sub test()
Dim olApp As Outlook.Application, olNs As Outlook.Namespace
Dim olFolder As Outlook.MAPIFolder, olMail As Outlook.MailItem
Dim eFolder As Outlook.Folder '~~> additional declaration
Dim i As Long
Dim x As Date, ws As Worksheet '~~> declare WS variable instead
Dim lrow As Long '~~> additional declaration
Set ws = Activesheet '~~> or you can be more explicit using the next line
'Set ws = Thisworkbook.Sheets("YourTargetSheet")
Set olApp = New Outlook.Application
Set olNs = olApp.GetNamespace("MAPI")
x = Date
For Each eFolder In olNs.GetDefaultFolder(olFolderInbox).Folders
'Debug.Print eFolder.Name
Set olFolder = olNs.GetDefaultFolder(olFolderInbox).Folders(eFolder.Name)
For i = olFolder.Items.Count To 1 Step -1
If TypeOf olFolder.Items(i) Is MailItem Then
Set olMail = olFolder.Items(i)
If InStr(olMail.Subject, "transactions") > 0 _
And InStr(olMail.ReceivedTime, x) > 0 Then
With ws
lrow = .Range("A" & .Rows.Count).End(xlup).Row
.Range("A" & lrow).Offset(1,0).value = olMail.Subject
.Range("A" & lrow).Offset(1,1).Value = olMail.ReceivedTime
.Range("A" & lrow).Offset(1,2).Value = olMail.SenderName
End With
End If
End If
Next i
Set olFolder = Nothing
Next eFolder
End Sub
Above takes care of all subfolders in Inbox.
Is this what you're trying?
To fix your error (olFolderInbox is a Outlook only constant, so you need to define it in vba that is not Outlook):
Const olFolderInbox = 6
'...
Set Fldr = olNs.GetDefaultFolder(olFolderInbox).Folders("PRE Customer")
Also to prevent missing Reference when run from another computer, I would:
Dim olApp As Object
Dim olNs As Object
Dim Fldr As Object
Dim olMail As Object
Dim i As Long
Set olApp = CreateObject("Outlook.Application")
'...
You might also want to disable ScreenUpdating, then enable it in Excel if you expect a long list.
UPDATE (Solution for all folders from a Root Folder)
I used something slightly different for comparing the dates.
Option Explicit
Private lRow As Long, x As Date, oWS As Worksheet
Sub GetFromInbox()
Const olFolderInbox = 6
Dim olApp As Object, olNs As Object
Dim oRootFldr As Object ' Root folder to start
Dim lCalcMode As Long
Set olApp = CreateObject("Outlook.Application")
Set olNs = olApp.GetNamespace("MAPI")
Set oRootFldr = olNs.GetDefaultFolder(olFolderInbox).Folders("PRE Customer")
Set oWS = ActiveSheet
x = Date
lRow = 1
lCalcMode = Application.Calculation
Application.Calculation = xlCalculationManual
Application.ScreenUpdating = False
GetFromFolder oRootFldr
Application.ScreenUpdating = True
Application.Calculation = lCalcMode
Set oWS = Nothing
Set oRootFldr = Nothing
Set olNs = Nothing
Set olApp = Nothing
End Sub
Private Sub GetFromFolder(oFldr As Object)
Dim oItem As Object, oSubFldr As Object
' Process all mail items in this folder
For Each oItem In oFldr.Items
If TypeName(oItem) = "MailItem" Then
With oItem
If InStr(1, .Subject, "transactions", vbTextCompare) > 0 And DateDiff("d", .ReceivedTime, x) = 0 Then
oWS.Cells(lRow, 1).Value = .Subject
oWS.Cells(lRow, 2).Value = .ReceivedTime
oWS.Cells(lRow, 3).Value = .SenderName
lRow = lRow + 1
End If
End With
End If
Next
' Recurse all Subfolders
For Each oSubFldr In oFldr.Folders
GetFromFolder oSubFldr
Next
End Sub

Resources