How to reference the original mail of a reply? - vba

I have code which when I reply to a mail asks which folder the reply should be saved to.
I need to extend it to move the mail I replied to (the parent mail) to also save in the folder I chose for the reply mail.
I feel this can be done if I could make an object of the Parent mail with maybe Conversation ID?
Public Sub Application_ItemSend(ByVal Item As Object, Cancel As Boolean)
Dim myFolder As MAPIFolder
Dim myOlApp As Outlook.Application
Dim myOlExp As Outlook.Explorer
If Environ("MailSave") = True Then
If TypeName(Item) = "MailItem" Then
Set myOlApp = CreateObject("Outlook.Application")
Set olNS = myOlApp.GetNamespace("MAPI")
Set myFolder = olNS.PickFolder
'todo
If Not (myFolder Is Nothing) Then
Set Item.SaveSentMessageFolder = myFolder
'Item.Parent.Move myFolder ---I tried this. But it is wrong I know
' MsgBox ("All moved")
End If
End If
End If
End Sub

You may look at the "In-Reply-To" header (exposed by the PR_IN_REPLY_TO_ID MAPI property), but these values are written after the ItemSend event is fired.
I'd suggest handling the MailItem.Reply event which is fired when the user selects the Reply action for an item, or when the Reply method is called for the item. Also you may be interested in the MailItem.Forward event which is fired when the user selects the Forward action for an item, or when the Forward method is called for the item.
Public WithEvents myItem As MailItem
Sub Initialize_Handler()
Set myItem = Application.ActiveInspector.CurrentItem
End Sub
Private Sub myItem_Reply(ByVal Response As Object, Cancel As Boolean)
Set Response.SaveSentMessageFolder = myItem.Parent
End Sub
So, following that way you will be able to access the original item and set the SaveSentMessageFolder property.

Related

Save attachments of incoming email with specific subject

On Outlook 365, so no rules + script allowed as I'm not full admin on the machine.
I need to check when mail arrives,
if it has some specific words in the subject
then save the attachment in a specific folder (it would be better with the name of the mail subject + datestamp) and then put the mail in the bin.
I tried the next code.
Option Explicit
Private WithEvents inboxItems As Outlook.Items
Private Sub Application_Startup()
Dim outlookApp As Outlook.Application
Dim objectNS As Outlook.NameSpace
Set outlookApp = Outlook.Application
Set objectNS = outlookApp.GetNamespace("MAPI")
Set inboxItems = objectNS.GetDefaultFolder(olFolderInbox).Items
End Sub
'--------------------- ok till here -----------
Private Sub inboxItems_ItemAdd(ByVal Item As Object)
On Error GoTo ErrorHandler
Dim Msg As Outlook.MailItem
Dim objAttachments As Outlook.Attachments
Set objAttachments = Msg.Attachments
If TypeName(Item) = "MailItem" Then
If InStr(Msg.Subject, "Magic Red Carpet") Then
objAttachments.SaveAsFile "C:\Users\xx12345\Desktop\vba\" & objAttachments.Msg.Subject&date
End If
End If
ErrorHandler:
MsgBox "dho!"
End Sub
You need to use the item object passed as a parameter to the ItemAdd event of the Items class in the code:
Private Sub inboxItems_ItemAdd(ByVal Item As Object)
On Error GoTo ErrorHandler
Dim objAttachments As Outlook.Attachments
Set objAttachments = Item.Attachments
If TypeName(Item) = "MailItem" Then
If InStr(Item.Subject, "Magic Red Carpet") Then
objAttachments.SaveAsFile "C:\Users\xx12345\Desktop\vba\" & objAttachments.Msg.Subject&date
End If
End If
End Sub
Note, the Subject string may contain symbols not allowed in file names. So, I'd recommend checking for them before calling the SaveAsFile method.
Also you may consider handling the NewMailEx event of the Application class instead. This event fires once for every received item that is processed by Microsoft Outlook. The item can be one of several different item types, for example, MailItem, MeetingItem, or SharingItem. The NewMailEx event fires when a new message arrives in the Inbox and before client rule processing occurs. You can use the Entry ID returned in the EntryIDCollection array to call the NameSpace.GetItemFromID method and process the item.

Reference a Shared Sub Folder in an inbox

I'm looking to modify my VBA code to reference a shared inbox that has a subfolder inside of it. The commented out code worked with my main inbox folder and a sub folder called test. I've tried to use the getSharedDefaultfolder method but the code currently does not detect an email being placed in the subfolder of my shared inbox. Does anyone have any thoughts or recommendations?
Public WithEvents objInbox As Outlook.Folder
Public WithEvents objInboxItems As Outlook.Items
Private Sub Application_Startup()
Dim olNs As Outlook.NameSpace
Dim Inbox As Outlook.MAPIFolder
Set olNs = Application.GetNamespace("MAPI")
Set shrdRecip = olNs.CreateRecipient(test#outlook.com)
Set Inbox = olNs.GetSharedDefaultFolder(shrdRecip, olFolderInbox).Folders("test")
'Set objInbox = Outlook.Application.Session.GetDefaultFolder(olFolderInbox).Folders("test")'
'Set objInboxItems = objInbox.Items'
Set objInboxItems = Inbox.Items
End Sub
Private Sub objInboxItems_ItemAdd(ByVal Item As Object)
Dim objMail As Outlook.MailItem
Dim objForward As Outlook.MailItem
MsgBox Item.Subject
If TypeOf Item Is MailItem Then
Set objMail = Item
MsgBox objMail.UnRead
If (objMail.UnRead Or False) Then
Set objForward = objMail.Forward
With objForward
.Subject = "Custom Subject"
.HTMLBody = "<HTML><BODY>Type body here. </BODY></HTML>" & objForward.HTMLBody
.Recipients.Add (usr#yahoo.com)
.Recipients.ResolveAll
.Send
MsgBox Item.Subject
End With
End If
End If
End Sub
Sub MyTEST()
End Sub```
You need to add the shared folder/store to your Outlook profile if you want to get events fired in VBA.
Also make sure an instance of the Items class was initialized correctly in the code to get the events fired.
I'd suggest calling the Recipient.Resolve method before accessing the shared folder, it attempts to resolve a Recipient object against the Address Book.
Are you sure objInboxItems is not null? By default, GetSharedDefaultFolder only returns the folder but not its subfolders unless the shared mailbox is added to the profile as a delegate mailbox and and all its folders are synchronized by Outlook.

Outlook VBA move mail in subfolder which hods mail of same subject

I'd like to do the following:
On the event of receiving a new mail the subject of the mail should be checked and if the same subject exists already in any subfolder the mail shall be moved to that same subfolder. In case the same mail can't be found it shall remain in the normal inbox folder.
The target folder as such has no logical connection to the mail, so it is not called like the mail or the mail sender or something like that. It is only the folder which holds one or mails with the same subject.
I managed - by browsing through this forum - to identify the event, the subject of the mail and to perform the actual move.
What I did not manage is:
1. to create a search logic to find already existing mails with the same subject in any folder
2.to return the found folder to use it as the target destination.
This is how it looks up till now and it manages to show a message...
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
Dim Msg As Outlook.MailItem
Dim MoveToFolder As Outlook.MAPIFolder
If TypeName(Item) = "MailItem" Then
Set Msg = Item
MsgBox "Here the folder must be found for '" & Msg.Subject & "'."
'Msg.Move MoveToFolder
End If
ProgramExit:
Exit Sub
ErrorHandler:
MsgBox Err.Number & " - " & Err.Description
Resume ProgramExit
End Sub
On top: Is there a specific smart way to do the same on other events like for example "SentMails"?
Thanks a lot for any support.
Ralf
You can use the AdvancedSearch method of the Application class which performs a search based on a specified DAV Searching and Locating (DASL) search string. You can read more about that method in the Advanced search in Outlook programmatically: C#, VB.NET article. So, you can find items with the same subject and then get their Parent property value which stands for the folder where they are stored.
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
Is there a specific smart way to do the same on other events like for example "SentMails"?
You may consider handling the ItemSend event of the Application class which is fired whenever an Microsoft Outlook item is sent, either by the user through an Inspector (before the inspector is closed, but after the user clicks the Send button) or when the Send method for an Outlook item. In the event handler you can set the SaveSentMessageFolder property which allows to set a Folder object that represents the folder in which a copy of the e-mail message will be saved after being sent.

VBA Outlook userform prompt

I have a userform that is prompted when I send emails (works great. not the problem) and from there when I click the buttons on the form it moves that email to the respective folder.
What I now want is for that same userform (rather, a duplicate) to be prompted when a message in my inbox goes from unread to read. The buttons on the userform would then move that message to the respective folder.
Code to bring up userform when sending emails:
Private Sub Application_ItemSend(ByVal Item As Object, cancel As Boolean)
UserForm1.Show vbModal
cancel = False
End Sub
Code snippet for a button of the userform:
Private Sub CommandButton1_Click()
On Error GoTo error_movemessage
Dim myolapp As New Outlook.Application
Dim mynamespace As Outlook.NameSpace
Dim myinbox As Outlook.MAPIFolder
Dim mydestfolder As Outlook.MAPIFolder
Dim myitems As Outlook.Items
Dim myItem As Object
Set mynamespace = myolapp.GetNamespace("MAPI")
Set myinbox = Session.GetDefaultFolder(olFolderInbox).Parent.Folders("RetainPermanently")
Set myitems = myinbox.Items
Set mydestfolder = myinbox
Set myItem = Application.ActiveInspector.CurrentItem
myItem.Move mydestfolder
Unload Me
exit_CommandButton1_Click:
Exit Sub
error_movemessage:
MsgBox "ERROR! " & Err.Description
Resume exit_CommandButton1_Click
End Sub
I searched far and wide for pieces to this puzzle and ultimately ended up unsuccessful. Thank you in advance!
Update:
Private Sub getselecteditem_click()
Dim oApp As New Outlook.Application
Dim oExp As Outlook.Explorer
Dim oSel As Outlook.Selection
Dim oItem As Object
Set oExp = oApp.Application
Set oSel = oExp.Selection
For i = 1 To oSel.Count
Set oItem = oSel.Item(i)
If oItem.Class = olMail Then
End If
Next i
End Sub
Sub oItem_PropertyChange(ByVal Name As String)
Select Case Name
Case "UnRead"
If oItem.UnRead = False Then
UserForm2.Show vbModal
End If
End Select
End Sub
Still doesn't work however.
I realized that I've been making this much harder than it needs to be. I can simply get it to pull up the prompt whenever i load a mailitem that happens to be unread. Here is an update:
Private Sub Application_ItemLoad(ByVal Item As Object)
If Item.Class = olMail Then
If Item.UnRead Then
UserForm2.Show vbModal
End If
End If
End Sub
Firstly, if you move an item to a different folder when the message is sent, you are asking for trouble - if you want the message to be saved in a folder other than Sent Items, set the MailItem.SaveSentMessageFolder property.
To move a message when its read state changes, track the Explorer.SelectionChange event. When SelectionChange event fires, start tracking the events on multiple messages from the Explorer.Selection collection (there can be more than one, but you can get away with just the first one as a proof of concept). When MailItem.PropertyChange event fires on the Unread property, display your prompt and move the message.

Track Email Category change in public shared folder only if I make the change

I have code to track changes in the Category of emails in a Public (Shared) Folder.
I have set up the code to be able to switch it "on/off", and this code is in ThisOutlookSession:
Private WithEvents myOlItems As Outlook.Items
Private Sub myOlItems_ItemChange(ByVal Item As Object)
Dim prompt As String
prompt = Item.Categories
If MsgBox(prompt, vbYesNo + vbQuestion) = vbYes Then
'do stuff
End If
End Sub
Sub TriggerOn()
Dim olApp As Outlook.Application
Dim objNS As Outlook.NameSpace
Set olApp = Outlook.Application
Set objNS = olApp.GetNamespace("MAPI")
Set myOlItems = Outlook.Session.Folders("SampleMailBox").Folders("Inbox").Items
End Sub
Sub TriggerOff()
Dim olApp As Outlook.Application
Dim objNS As Outlook.NameSpace
Set olApp = Outlook.Application
Set objNS = olApp.GetNamespace("MAPI")
Set myOlItems = Nothing
End Sub
Since this a Public Shared Folder, if any other user makes a change, the code will be triggered.
I want to track only the changes that I make.
You can check out the CurrentUser property of the Namespace class. The property returns the display name of the currently logged-on user as a Recipient object. So, if it is you, you can run the code (display a message box and etc.).
Check the value of the PR_LAST_xyz properties (PR_LAST_MODIFIER_NAME, PR_LAST_MODIFIER_ENTRYID, etc.) These properties can be accessed using MailItem.PropertyAccessor.GetProperty. Take a look at the messages with OutlookSpy (I am its author - click IMessage button) to see the available properties and their values as well as the property DASL names that you will need to use when calling GetProperty.
Another solution would be to use MailItem.Write event. If you assume that the category can be modified from the right click on the message only and a message must be selected before it is modified, you can track the Explorer.SelectionChange event, set up event sinks on the selected messages, and track the MailItem.Write event.