I'm trying to read my Sharepoint Calendar entries and then add one to my personal calendar with an offest of 4 hours on the same day.
The following creates a new entry but my For Each loop doesn't seem to work as it always jumps back to the main Function when I try to create a new Entry with the Date and Time read from the Variable "newStart".
Public newStart As String
Sub ReadEntries()
Dim oApp As Outlook.Application
On Error Resume Next
' check if Outlook is running
Set oApp = GetObject("Outlook.Application")
If Err <> 0 Then
'if not running, start it
Set oApp = CreateObject("Outlook.Application")
End If
Set olApp = New Outlook.Application
Set olFldr = olApp.GetNamespace("MAPI").Folders("Other Calendars").Folders("FOLDERNAME")
For Each Items In olFldr
If olFldr.Items.Subject = "Given Entry Title" Then
newStart = olFldr.Items.Start
CreateStandby
End If
Next
Set oObject = Nothing
Set oApp = Nothing
End Sub
Sub CreateStandby()
Dim standbyEntry As Object
Set standbyEntry = Application.CreateItem(olAppointmentItem)
standbyEntry.Subject = "New Entry Title"
standbyEntry.Start = newStart
standbyEntry.Duration = 240
standbyEntry.BusyStatus = olOutOfOffice
standbyEntry.Send
standbyEntry.Save
End Sub
Option Explicit ' Consider this mandatory
' Tools | Options | Editor tab
' Require Variable Declaration
' If desperate declare as Variant
' Avoid global variables unless there is no other way
' Inevitably the name will be non-unique
' You need something impossible to reproduce in other code
' Public newStart As String
Sub ReadEntries()
Dim olfldr As folder
Dim myItem As Object
' The less good version of GetObject was incorrectly done.
' Must return to regular error handling. On Error GoTo 0
'
' This shows the ideal, one line only, error bypass.
' https://stackoverflow.com/questions/22059917/how-to-verify-outlook-session-is-open-or-not-using-vba
'
' Unnecessary when code is in Outlook.
Set olfldr = Session.folders("Other Calendars").folders("FOLDERNAME")
For Each myItem In olfldr.Items
If myItem.Class = olAppointment Then
If myItem.subject = "Given Entry Title" Then
CreateStandby myItem.Start, myItem.Duration
End If
End If
Next
End Sub
Sub CreateStandby(itmStart As Date, itmDuration As Long)
Dim standbyEntry As AppointmentItem
Set standbyEntry = CreateItem(olAppointmentItem)
With standbyEntry
.subject = "New Entry Title"
' start 4 hours earlier
.Start = DateAdd("h", -4, itmStart)
' end at the same time
.Duration = itmDuration + 240
.Display
End With
End Sub
Related
I have code that reads mail to generate a task with the mail's content.
In a few cases this hits a problem, when reading the RTFbody from the mail, saying "not implemented".
Can I test against this? Like WHEN IS NULL ... which checks if a variable has appropriate content.
Sub CreateTempTaskFromMail()
Dim oMail As Outlook.MailItem
Set oMail = ActiveInspector.CurrentItem
Dim s, sNr As String
s = oMail.subject
Dim oTask As Outlook.TaskItem
Set oTask = CreateTaskWithTempFolder(s, False) ' Function creating and returing task
oTask.RTFBody = oMail.RTFBody
End sub
I tried to test several ways if RTFbody has a problem. All of these approaches throw an error.
If oMail.RTFBody Is Nothing Then Stop
If IsError(oMail.RTFBody) Then Stop
If IsMissing(oMail.RTFBody) Then Stop
If IsEmpty(oMail.RTFBody) Then Stop
If there is absolutely no real solution then
Option Explicit
Sub CreateTempTaskFromMail()
Dim oObj As Object
Dim oMail As mailItem
Dim oTask As TaskItem
Dim s As String
Set oObj = ActiveInspector.currentItem
If oObj.Class = olMail Then
Set oMail = oObj
s = oMail.subject
Set oTask = CreateTaskWithTempFolder(s, False) ' Function creating and returing task
' If you absolutely cannot determine the problem
' https://excelmacromastery.com/vba-error-handling#On_Error_Resume_Next
On Error Resume Next
oTask.RTFBody = oMail.RTFBody
If Err <> 0 Then
Debug.Print "Error was bypassed using a technique that is to be avoided."
Exit Sub
End If
' Consider mandatory AND as soon as possible
On Error GoTo 0
oTask.Display
Else
Debug.Print "not a mailitem"
End If
End Sub
Before accessing the RTFBody property in the code I'd suggest checking the item's type first to make sure such property exists for a specific item type:
If TypeOf item Is MailItem Then
' do whatever you need with RTFBody here
End If
Or
If TypeName(item) = "MailItem" Then
' do whatever you need with RTFBody here
End If
If you are using Office 2016 product, you should update office. It is early office 2016 build's bug.
can someone advise what have I done wrong on here? It is not picking up the emails the way it should (i.e. automatically download the attachments into a folder). There is no error messages, but simply no action (I went F8 but would not notice any irregularities).
Private WithEvents Items As Outlook.Items
Private Sub Application_Startup()
Dim olApp As Outlook.Application
Dim objNS As Outlook.NameSpace
Set olApp = Outlook.Application
Set objNS = olApp.GetNamespace("MAPI")
Set Items = objNS.GetDefaultFolder(olFolderInbox).Items
End Sub
Private Sub Items_ItemAdd(ByVal item As Object)
On Error GoTo ErrorHandler
'Only act if it's a MailItem
Dim Msg As Outlook.MailItem
If TypeName(item) = "MailItem" Then
Set Msg = item
'Change variables to match need. Comment or delete any part unnecessary.
If (Msg.SenderName = "test123#gmail.com") And _
(Msg.Subject = "Test123") And _
(Msg.Attachments.Count >= 1) Then
'Set folder to save in.
Dim olDestFldr As Outlook.MAPIFolder
Dim myAttachments As Outlook.Attachments
Dim Att As String
'location to save in. Can be root drive or mapped network drive.
Const attPath As String = "C:\Test\Test1\"
' save attachment
Set myAttachments = item.Attachments
Att = myAttachments.item(1).DisplayName
myAttachments.item(1).SaveAsFile attPath & Att
Msg.UnRead = False
End If
End If
ProgramExit:
Exit Sub
ErrorHandler:
MsgBox Err.Number & " - " & Err.Description
Resume ProgramExit
End Sub
Also, when I'm trying to F8 for errors, the VBA only goes through the first part of the code i.e. Private Sub Application_Startup(), I'm unable to test the other part {Private Sub Items_ItemAdd(ByVal item As Object)} cos the VBA simply denies going through it line by line (no error pop-ups or anything, it simply is not picking up the lines)
The problem is in the line
myAttachments.item(1).SaveAsFile attPath & Att
You are always picking attachment no 1, which might be something else than you think. Add a For Each around this, and you'll hopefully get some better results.
My guess is that your problem is this condition:
If (Msg.SenderName = "test123#gmail.com")
The MailItem.SenderName property returns the display name of the sender, which may not be the actual email address. You should be checking the MailItem.SenderEmailAddress property instead.
If the email you're trying to match is an Exchange address (ie, it's from someone in your office's Outlook account), the MailItem.SenderEmailAddress will return an incomprehensible string that you'll need to resolve to an actual email. In that case, you'd need to check the MailItem.Sender.GetExchangeUser().PrimarySmtpAddress property instead.
For that reason, I like to use an "emailMatches" function that checks both scenarios. Then your condition would be something like:
If emailMatches(Msg, "test123#company.com")
Here's the function I use:
Function emailMatches(mItem As Object, addressToMatch As String) As Boolean
Dim goAhead As Boolean
goAhead = False
If UCase(mItem.SenderEmailAddress) = UCase(addressToMatch) Then
goAhead = True
ElseIf Left(mItem.SenderEmailAddress, 5) = "/O=EX" Then
If UCase(mItem.Sender.GetExchangeUser().PrimarySmtpAddress) = UCase(addressToMatch) Then
goAhead = True
End If
End If
emailMatches = goAhead
End Function
I'm working within MS Access 2013 and MS Outlook 2013 on Windows 10 and I have a Access DB with a "Navigation Subforms" paradigm that allows sending a single e-mail on two separate occasions.
I'm trying to write code to do the following:
when a new e-mail is sent,
I want to save it as a .msg file on disk automatically.
From what I can tell, it seems the way to do this is via trapping the .ItemAdd event that fires on Outlook Sent Folder within Access, and in there executing the .SaveAs method.
I was trying to implement a solution based on these two answers:
How to Trap Outlook Events from Excel Application
Utilizing Outlook Events From Excel
but I just can't seem to combine the two and make the event fire.
My feeling is that either I'm not referencing/setting things correctly or the execution reaches an end before the e-mail is moved from the Outbox Folder to the Sent Folder, but I'm not sure.
How can I do this?
Thanks for reading, code follows:
My current class module - "cSentFolderItem"
Option Explicit
Public WithEvents myOlItems As Outlook.items
Private Sub Class_Initialize()
Dim oNS As NameSpace
Dim myOL As Outlook.Application
Set myOL = New Outlook.Application
Set oNS = myOL.GetNamespace("MAPI")
Set myOlItems = oNS.GetDefaultFolder(olFolderSentMail).items
End Sub
Private Sub myOlItems_ItemAdd(ByVal Item As Object)
Debug.Print "I got a new item on Sent box!"
Dim myOlMItem As Outlook.MailItem
Set myItem = myOlItems.items(email_subject)
myItem.Display
myItem.SaveAs "C:\Users\XXXXXX\Desktop\mail_test.msg", olMSGUnicode
End Sub
"Regular" code:
Public Function GetApplication(Class As String) As Object
'Handles creating/getting the instance of an application class
Dim ret As Object
On Error Resume Next
Set ret = GetObject(, Class)
If Err.Number <> 0 Then
Set ret = CreateObject(Class)
End If
Set GetApplication = ret
On Error GoTo 0
End Function
Sub Test()
email_subject = "Mail test match string - [aaaa-mm-dd]"
Set myOlItems = New cSentFolderItem 'declare class module object
Dim MyOutlook As Outlook.Application
Set MyOutlook = GetApplication("Outlook.Application") 'trying to get correct application object
'The following code is a dummy e-mail creation, after which I press SEND:
Dim MyMail As Outlook.MailItem
varTo = "target_email#address.com"
varSubject = email_subject
varbody = "test line 1" & vbCrLf & "test line 2" & vbCrLf & "test line 2"
varSubject = Replace(varSubject, "[aaaa-mm-dd]", NOW())
Dim linhas() As String
linhas = Split(varbody, vbCrLf)
bodyHTMLtext = "<body>"
For i = 0 To UBound(linhas) - 1
bodyHTMLtext = bodyHTMLtext & linhas(i) & "<br>"
Next
bodyHTMLtext = bodyHTMLtext & linhas(UBound(linhas))
bodyHTMLtext = bodyHTMLtext & "</body>"
Set MyMail = MyOutlook.CreateItem(OLMAILITEM)
MyMail.To = varTo
MyMail.Subject = varSubject
MyMail.Display
MyMail.HTMLBody = bodyHTMLtext & MyMail.HTMLBody
AppActivate varSubject
'trying to leave Outlook object open:
''Cleanup after ourselves
'Set MyMail = Nothing
''MyOutlook.Quit
'Set MyOutlook = Nothing
End Sub
Ok, after some long hours, I figured it out, and got to the following solution.
My class module "MyOutlook" is:
Option Explicit
Public myOutlookApp As Outlook.Application
Public mySentFolder As Outlook.Folder
Public WithEvents myItems As Outlook.items
Private Sub Class_Initialize()
Set myOutlookApp = GetApplication("Outlook.Application")
Dim oNS As NameSpace
Set oNS = myOutlookApp.GetNamespace("MAPI")
Set mySentFolder = oNS.GetDefaultFolder(olFolderSentMail)
Set myItems = mySentFolder.items
End Sub
Private Sub myItems_ItemAdd(ByVal Item As Object)
Debug.Print "Got_EMAIL!!! Looking for subject = " & email_subject
'"e-mail_subject" is Public a string, assigned in another part of the program
If Item.Subject = email_subject Then
Item.SaveAs "C:\Users\640344\Desktop\mail_test.msg", olMSGUnicode
End If
End Sub
Where GetApplication is:
Function GetApplication(Class As String) As Object
'Handles creating/getting the instance of an application class
'If there exists one already (in my case, Outlook already open),
'it gets its name, else it creates one
Dim ret As Object
On Error Resume Next
Set ret = GetObject(, Class)
If Err.Number <> 0 Then
Set ret = CreateObject(Class)
If Class = "Outlook.Application" Then
'Outlook wasn't opened, so open it
ret.Session.GetDefaultFolder(olFolderInbox).Display
ret.ActiveExplorer.WindowState = olMaximized
ret.ActiveExplorer.WindowState = olMinimized
End If
End If
Set GetApplication = ret
On Error GoTo 0
End Function
Note that I added the 3 lines of code after 'Outlook wasn't opened, so open it because otherwise I would get an error. It's not a bad idea for my users that the program opens Outlook, anyway.
On the "regular" code part of my project, outside any procedure, I declare:
Public myOutlook As myOutlook
Then, on my project's "main" sub:
Set myOutlook = New myOutlook
'[...]
'Code where entire program runs
'[...]
Set myOutlook = Nothing
This way, myOutlook object (and its variables) "lives" the entire time the program (with its Navigation Forms) is running, and is waiting to trap _ItemAdd events on the default Sent Folder of Outlook.
Note that I look only for e-mails with subject equal to the email_subject string, because I don't want to save all sent e-mails, just the one sent by using the program, and I have code to assign my desired subject to that string.
Regretfully I have no formal background in VBA, but I have been able to learn quite a bit from sites like this.
Problem Statement:
I have a few emails with contain information that needs to be stored in excel. Fortunately I do have working script for that. Not provided to keep this somewhat shorter
The problem that I am facing is that capturing the right email from Microsoft Outlook 2010 and storing the data WITHOUT manual intervention.
The Email will contain a specific word/phrase, "EVEREST". Obviously it is not the only email received. It contains no attachments, and will come from various senders.
I have tried various macros I have found on-line to pull the message from the inbox, but none of them have worked for me.
So I have a macros that will pull messages from a personal folder, that macro then runs another macros that stores the contents of the email to excel, then it moves the message to its final resting place (another personal Folder) currently they all work fine together, but require manual intervention to complete the task. After the message is moved to the personal folder I simply click on a Quick Access Toolboar Icon mapped to a macro
To get the message moved over the personal folder i have a rule set up to move the message based on the word "EVEREST" and runs the initial script.
The problem with all of this is that the message will get moved to the folder, but needs manual intervention to complete the task. I would like it to run automatically.
I have been fumbling around with this for the past 2 months and seem to be in a stalemate. I would greatly appreciate your feedback and assistance.
The following is what I have so far.
My outlook rule set is:
Apply this rule after the message arrives
with "EVEREST" in the subject
and on this computer only
move it to the "EVEREST PRI" folder
and run "Project1.ThisOutlookSession.Everest"
' I believe these were put here when I was trying to run '
' everything via VBA macros, vice using the rule set above '
CLass Module (1)
Option Explicit
Private WithEvents Items As Outlook.Items
Private WithEvents olInboxItems As Items
' ThisOutlookSession contains the following scripts '
'This is the script that is run from the outlook rules '
' all it does is calls the "OCF" Sub below '
Sub Everest(email As MailItem)
OCF
End Sub
'This scipt opens the "EVEREST PRI" personal sub folder'
' and calls the "Prepwork" sub below '
Sub OCF()
Dim objOlApp As Outlook.Application
Dim Ns As Outlook.NameSpace
Dim objFolder As Outlook.Folder
Dim EmailCount As Integer
Set objOlApp = CreateObject("Outlook.Application")
Set Ns = Session.Application.GetNamespace("MAPI")
Set objFolder = Ns.Folders("Personal Folders").Folders("Archives").Folders("EVEREST PRI")
Set objOlApp.ActiveExplorer.CurrentFolder = objFolder
Set objFolder = Nothing
Set objOlApp = Nothing
Prepwork
End Sub
'I had hoped that the following routine would do the rest of the work '
'but it doesn't do it all the time. Most the time the message hasn't been '
'moved to the personal folder before its kicked off. '
'So I thought I would call another macro to play catch up "Wait" below '
Sub Prepwork()
Dim objOlApp As Outlook.Application
Dim Ns As Outlook.NameSpace
Dim objFolder As Outlook.Folder
Dim EmailCount As Integer
Set objOlApp = CreateObject("Outlook.Application")
Set Ns = Session.Application.GetNamespace("MAPI")
Set objFolder = Ns.Folders("Personal Folders").Folders("Archives").Folders("EVEREST PRI")
Set objOlApp.ActiveExplorer.CurrentFolder = objFolder
EmailCount = objFolder.Items.count
If EmailCount = 1 Then
'MsgBox "A COMSPOT has been recieved, acknowledge to update the chart'
' I tried adding this msgbox to provide some time delay, although '
' it has worked from time to time, it still requires manual '
' intervention, which is not desired. '
CopyToExcel
' CopyToExcel is the macro that writes my information to the '
' Spreadsheet. This script has been flawless and I have created '
' a Clickable ICON in the Quick Access Toolboar. '
ElseIf EmailCount = 0 Then
Wait
End If
End Sub
'The following "Wait Script was added, hoping to give time for the other '
'macros to finish, but i suspect they are all linked together, and wont '
'finish until all macroshave finished including the previously mentioned '
' "CopyToExcel" macro. '
' I have also tried to run this macro from the outlook rules, no joy......'
Sub Wait() '(email As MailItem)
' this provides a 5 second wait'
Sleep (5000)
Dim objOlApp As Outlook.Application
Dim Ns As Outlook.NameSpace
Dim objFolder As Outlook.Folder
Dim EmailCount As Integer
Set objOlApp = CreateObject("Outlook.Application")
Set Ns = Session.Application.GetNamespace("MAPI")
Set objFolder = Ns.Folders("Personal Folders").Folders("Archives").Folders("EVEREST PRI")
Set objOlApp.ActiveExplorer.CurrentFolder = objFolder
EmailCount = objFolder.Items.count
If EmailCount = 1 Then
'MsgBox "A COMSPOT has been recieved, acknowledge to update the chart"
CopyToExcel
ElseIf EmailCount = 0 Then
' MsgBox "The second Marco (Wait) did not locate a Message in the PRI Folder. Run the script from the Quick Access Toolboar"
End If
End Sub
' The following macro moves each of the selected items on the screen to an'
' Archive folder. I have not had any problems with this macro '
' This macro is called from the "CopyToExcel" macro. (not shown as it '
' has also worked fine since incorporating it '
Sub ArchiveItems() ' Moves each of the selected items on the screen to an Archive folder.
Dim olApp As New Outlook.Application
Dim olExp As Outlook.Explorer
Dim olSel As Outlook.Selection
Dim olNameSpace As Outlook.NameSpace
Dim olArchive As Outlook.Folder
Dim intItem As Integer
Set olExp = olApp.ActiveExplorer
Set olSel = olExp.Selection
Set olNameSpace = olApp.GetNamespace("MAPI")
' This assumes that you have an Inbox subfolder named Archive.
Set olArchive = olNameSpace.Folders("Personal Folders").Folders("Archives").Folders("EVEREST Archive")
For intItem = 1 To olSel.count
olSel.Item(intItem).Move olArchive
Next intItem
OIB
End Sub
' The following macro simply returns the view to the inbox folder, '
' Thus returning everything to Normal '
' The Ideal of returning to which every folder, or message was open at '
' the time the EVEREST message first arrived I thought would be to '
' complicated, but if any body could solve that... AMAZING.... '
Sub OIB()
Dim objOlApp As Outlook.Application
Dim Ns As Outlook.NameSpace
Dim objFolder As Outlook.Folder
Set objOlApp = CreateObject("Outlook.Application")
Set objFolder = Session.GetDefaultFolder(olFolderInbox)
Set objOlApp.ActiveExplorer.CurrentFolder = objFolder
Set objFolder = Nothing
Set objOlApp = Nothing
End Sub
There is no need to select, you already have the required "email" passed as a parameter by the rule.
The run a script code will look something like this.
Sub Everest(email As MailItem)
Dim Ns As NameSpace
'Dim inboxFolder As Folder
Dim olArchive As Folder
Set Ns = GetNamespace("MAPI")
CopyToExcelWithParameter email
'ArchiveItems
Set olArchive = Ns.Folders("Personal Folders")
Set olArchive = olArchive.Folders("Archives")
Set olArchive = olArchive.Folders("EVEREST Archive")
email.Move olArchive
' Edit: Just realized this was due to
' unnecessary folder selecting that is now gone
' This is unnecessary now as well
'OIB
'Set inboxFolder = Ns.GetDefaultFolder(olFolderInbox)
'Set ActiveExplorer.CurrentFolder = inboxFolder
Set Ns = Nothing
Set olArchive = Nothing
'Set inboxFolder = Nothing
End Sub
You will have to rewrite CopyToExcel to take email as a parameter
Sub CopyToExcelWithParameter (email as mailitem)
' code that processes "email" directly, not a selection
Debug.Print "Do something with " & email.subject
End Sub
I am attempting to code a way to automate filing of emails. I file all of my emails in a pretty detailed set of sub-folders in my inbox. I have MANY subfolders that help me organize my emails but this leads to a lot of extra time being spent in cleaning out my inbox (by filing emails to the relevant sub-folder). I would like to automate this so that I can select an email in my inbox and run the macro to display a list of folders that emails in the same conversation thread have already been filed in and allow me to select which one to save the selected email to. I have found several sample codes that are close but nothing that really does this action.
http://blog.saieva.com/2010/03/27/move-messages-to-folders-with-outlook-vba/
shows how to move messages to sub-folders when you know what sub-folder you want the email to go to. This doesn't work for my situation because I want the macro to give me a list of "recommended" folders.
I thought the below code may be a good place to start if I could figure out a way to loop through each "child" (not sure if that is the right word) of the conversation for the selected email and move the selected to the folder if the user selects "Yes" in the MsgBox.
Public Sub GetItemsFolderPath()
Dim obj As Object
Dim F As Outlook.MAPIFolder
Dim convItemFolders As Outlook.MAPIFolder
Dim msg$
Dim rootitemcount
Set obj = Application.ActiveWindow
If TypeOf obj Is Outlook.Inspector Then
Set obj = obj.CurrentItem
Else
Set obj = obj.Selection(1)
End If
Set F = obj.Parent
msg = " The path is: " & F.FolderPath & rootitemcount & vbCrLf
msg = msg & "Switch to the folder?"
If MsgBox(msg, vbYesNo) = vbYes Then
Set Application.ActiveExplorer.CurrentFolder = F
End If
End Sub
I am having trouble putting together the loop that could make this work. Does anyone have any suggestions for how to use the above or any other options?
Edit
Not sure really how to show my next steps on this without "answering" my own question. This is my first question so I don't know all of the rules yet, if this is wrong please let me know so I can fix it. I'm not fully finished but I've gotten a lot closer with the help of the below answer. Below is my updated code:
Public Sub GetConverstationInformation()
Dim host As Outlook.Application
Set host = ThisOutlookSession.Application
' Check for Outlook 2010
If Left(host.Version, 2) = "14" Then
Dim selectedItem As Object
Dim theMailItem As Outlook.mailItem
' Get the user's currently selected item.
Set selectedItem = host.ActiveExplorer.Selection.item(1)
' Check to see if the item is a MailItem.
If TypeOf selectedItem Is Outlook.mailItem Then
Set theMailItem = selectedItem
' Check to see that the item's current folder
' has conversations enabled.
Dim parentFolder As Outlook.folder
Dim parentStore As Outlook.store
Set parentFolder = theMailItem.Parent
Set parentStore = parentFolder.store
If parentStore.IsConversationEnabled Then
' Try and get the conversation.
Dim theConversation As Outlook.conversation
Set theConversation = theMailItem.GetConversation
If Not IsNull(theConversation) Then
' Outlook provides a table object
' the contains all of the items in the
' conversation.
Dim itemsTable As Outlook.table
Set itemsTable = theConversation.GetTable
' Get the Root Items
' Enumerate the list of items
' only writing out data for MailItems.
' A conversation can contain other items
' like MeetingItems.
' Then use a helper method and recursion
' to walk all the items in the conversation.
Dim group As Outlook.simpleItems
Set group = theConversation.GetRootItems
Dim obj As Object
Dim fld As Outlook.folder
Dim mi As Outlook.mailItem
'Dim i As Long
For Each obj In group
If TypeOf obj Is Outlook.mailItem Then
Set mi = obj
Set fld = mi.Parent
'For i = 1 To group.Count
Me.ListBox1.AddItem fld.Name
'mi.Sender & _
'" sent the message '" & mi.Subject & _
'"' which is in '" &
'& "'."
'Next i
End If
GetConversationDetails mi, theConversation
Next obj
Else
MsgBox "The currently selected item is not a part of a conversation."
End If
Else
MsgBox "The currently selected item is not in a folder with conversations enabled."
End If
Else
MsgBox "The currently selected item is not a mail item."
End If
Else
MsgBox "This code only works with Outlook 2010."
End If
End Sub
Private Sub GetConversationDetails(anItem As Object, theConversation As Outlook.conversation)
Dim group As Outlook.simpleItems
Set group = theConversation.GetChildren(anItem)
If group.Count > 0 Then
Dim obj As Object
Dim fld As Outlook.folder
Dim mi As Outlook.mailItem
'Dim i As Long
'For i = 1 To group.Count(obj)
For Each obj In group
If TypeOf obj Is Outlook.mailItem Then
Set mi = obj
Set fld = mi.Parent
'Dim counter
Me.ListBox1.AddItem fld.Name
'mi.Sender & _
'" sent the message '" & mi.Subject & _
'"' which is in '" &
'& "'."
End If
GetConversationDetails mi, theConversation
Next obj
'Next i
End If
End Sub
Private Sub UserForm_Initialize()
GetConverstationInformation
End Sub
I dropped this into a userform with a listbox. My intention is to allow only unique folder names to be added. Once that is accomplished I would like to add a button that can be clicked to file the selected email in the folder chosen from the listbox. Does anyone have any notes/good starting places on these next steps? I have been searching online for different ways to do this but I keep coming across long sub's and I have to imagine there is a more elegant solution. I'll update again if I find something that works. Thanks again for your help!
It looks like you are interested in the GetConversation method which returns a Conversation object that represents the conversation to which this item belongs.
Private Sub DemoConversation()
Dim selectedItem As Object = Application.ActiveExplorer().Selection(1)
' For this example, you will work only with
'MailItem. Other item types such as
'MeetingItem and PostItem can participate
'in Conversation.
If TypeOf selectedItem Is Outlook.MailItem Then
' Cast selectedItem to MailItem.
Dim mailItem As Outlook.MailItem = TryCast(selectedItem, Outlook.MailItem)
' Determine store of mailItem.
Dim folder As Outlook.Folder = TryCast(mailItem.Parent, Outlook.Folder)
Dim store As Outlook.Store = folder.Store
If store.IsConversationEnabled = True Then
' Obtain a Conversation object.
Dim conv As Outlook.Conversation = mailItem.GetConversation()
' Check for null Conversation.
If conv IsNot Nothing Then
' Obtain Table that contains rows
' for each item in Conversation.
Dim table As Outlook.Table = conv.GetTable()
Debug.WriteLine("Conversation Items Count: " + table.GetRowCount().ToString())
Debug.WriteLine("Conversation Items from Table:")
While Not table.EndOfTable
Dim nextRow As Outlook.Row = table.GetNextRow()
Debug.WriteLine(nextRow("Subject") + " Modified: " + nextRow("LastModificationTime"))
End While
Debug.WriteLine("Conversation Items from Root:")
' Obtain root items and enumerate Conversation.
Dim simpleItems As Outlook.SimpleItems = conv.GetRootItems()
For Each item As Object In simpleItems
' In this example, enumerate only MailItem type.
' Other types such as PostItem or MeetingItem
' can appear in Conversation.
If TypeOf item Is Outlook.MailItem Then
Dim mail As Outlook.MailItem = TryCast(item, Outlook.MailItem)
Dim inFolder As Outlook.Folder = TryCast(mail.Parent, Outlook.Folder)
Dim msg As String = mail.Subject + " in folder " + inFolder.Name
Debug.WriteLine(msg)
End If
' Call EnumerateConversation
' to access child nodes of root items.
EnumerateConversation(item, conv)
Next
End If
End If
End If
End Sub
Private Sub EnumerateConversation(item As Object, conversation As Outlook.Conversation)
Dim items As Outlook.SimpleItems = conversation.GetChildren(item)
If items.Count > 0 Then
For Each myItem As Object In items
' In this example, enumerate only MailItem type.
' Other types such as PostItem or MeetingItem
' can appear in Conversation.
If TypeOf myItem Is Outlook.MailItem Then
Dim mailItem As Outlook.MailItem = TryCast(myItem, Outlook.MailItem)
Dim inFolder As Outlook.Folder = TryCast(mailItem.Parent, Outlook.Folder)
Dim msg As String = mailItem.Subject + " in folder " + inFolder.Name
Debug.WriteLine(msg)
End If
' Continue recursion.
EnumerateConversation(myItem, conversation)
Next
End If
End Sub
Thanks for your hard work! I wanted the same functionality and expanded on your code to add a listbox to select a folder and only allow unique folder names to be added to the listbox. I also added code to move the emails after a folder is selected. The finished code is working in Outlook 2016 and hosted on GitHub since listbox files are stored as binaries and cannot be shown here.
GitHub: outlook-move-to-thread
To update listbox and not allow duplicates in GetConversationInformation(),
For Each obj In group
If TypeOf obj Is Outlook.mailItem Then
' If ROOT item is an email, add it to ListBox1
Set mi = obj
Set fld = mi.Parent
' Don't include duplicate folders
IsInListBox = False
For i = 0 To Me.ListBox1.ListCount - 1
If Me.ListBox1.Column(0, i) = fld.FolderPath Then
IsInListBox = True
End If
Next
If (InStr(fld.FolderPath, "Inbox") = 0) And _
(InStr(fld.FolderPath, "Sent Items") = 0) And _
(IsInListBox = False) Then
Me.ListBox1.AddItem fld.FolderPath
End If
End If
GetConversationDetails mi, theConversation
Next obj
To update listbox and not allow duplicates in GetConversationDetails(),
' Don't include generic folders
If (InStr(fld.FolderPath, "Inbox") = 0) And _
(InStr(fld.FolderPath, "Sent Items") = 0) Then
' Don't include duplicate folders
IsInListBox = False
For i = 0 To Me.ListBox1.ListCount - 1
If Me.ListBox1.Column(0, i) = fld.FolderPath Then
IsInListBox = True
End If
Next
' Add to ListBox1
If IsInListBox = False Then
Me.ListBox1.AddItem fld.FolderPath
End If
End If