Move Email with ItemAdd - vba

I'm attempting to move email with specific subject when received.
The mail is still in my Inbox. I've tested by sending mail from my account with specific subject.
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
Private Sub Items_ItemAdd(ByVal item As Object)
On Error GoTo ErrorHandler
Dim Msg As Outlook.MailItem
Set myInbox = GetNamespace("MAPI").GetDefaultFolder(olFolderInbox)
If TypeName(item) = "MailItem" Then
Set Msg = item
If InStr(0, Msg.Subject, "Testing Subject", vbTextCompare) > 0 Then
Set fldr = Outlook.Session.GetDefaultFolder(olFolderInbox).Folders("Testing")
Msg.Move fldr
End If
End If
ProgramExit:
Exit Sub
ErrorHandler:
MsgBox Err.Number & " - " & Err.Description
Resume ProgramExit
End Sub
I created this macro in ThisOutlookSession.

I think you may have an error with the naming of your Sub which means it doesn't fire
Items_ItemAdd => inboxItems_ItemAdd
As an addendum: I recently implemented a RegEx filter to incoming e-mails as I found I couldn't easily use rules to filter out some junk e-mail coming my way. This should be able to adapted to your needs (I've added the rule I think should work for you, but it's untested)
Within the 'ThisOutlookSession'
Private Sub Application_NewMailEx(ByVal EntryIDCollection As String)
On Error Resume Next
Call RegExFilterRules(EntryIDCollection)
End Sub
Within a module
Sub RegExFilterRules(ItemID As String)
' Requires Reference: Microsoft Scripting Runtime
Dim ThisNamespace As Outlook.NameSpace: Set ThisNamespace = Application.GetNamespace("MAPI")
Dim Inbox As Outlook.MAPIFolder: Set Inbox = ThisNamespace.GetDefaultFolder(olFolderInbox)
Dim Junk As Outlook.MAPIFolder: Set Junk = ThisNamespace.GetDefaultFolder(olFolderJunk)
Dim oMsg As Outlook.MailItem: Set oMsg = ThisNamespace.GetItemFromID(ItemID, Inbox.StoreID)
If Not oMsg Is Nothing And oMsg.Class = olMail Then
'If FindPattern(oMsg.Subject, "^M\d+$") Then oMsg.Move Junk ' oMsg.Delete
If FindPattern(oMsg.Subject, "^Testing Subject") Then oMsg.Move Inbox.Folders("Testing")
End If
End Sub
Private Function FindPattern(Str As String, Pattern As String) As Boolean
Dim RegEx As Object: Set RegEx = CreateObject("vbscript.RegExp")
With RegEx
.Global = True
.IgnoreCase = True
.MultiLine = True
.Pattern = Pattern
FindPattern = .Test(Str)
End With
End Function

Related

Delete draft mail on close when not sent

I've got some draft mails with some buttons to copy and open them. Only a few values need to be filled in and then the mails will be sent. I want to keep the drafts. But if a mail is not sent, I would like to delete it because it is a copy. I'm working with the close event for a mail item, but I can't seem to find out how to delete it in that sub, tried many things. Anyone knows how to approach this?
Code I got so far in a module:
Dim itmevt As New CMailItemEvents
Public olMail As Variant
Public olApp As Outlook.Application
Public olNs As NameSpace
Public Fldr As MAPIFolder
Sub TeamcenterWEBAccount()
Dim i As Integer
Dim olMail As Outlook.MailItem
Set olApp = New Outlook.Application
Set olNs = olApp.GetNamespace("MAPI")
Set Fldr = olNs.GetDefaultFolder(olFolderDrafts)
For Each olMail In Fldr.Items
If InStr(olMail.Subject, "New account") <> 0 Then
Set NewItem = olMail.Copy
olMail.Display
Set itmevt.itm = olMail
Exit Sub
End If
Next olMail
End Sub
Code in the CMailItemEvents class module:
Option Explicit
Public WithEvents itm As Outlook.MailItem
Private Sub itm_Close(Cancel As Boolean)
Dim blnSent As Boolean
On Error Resume Next
blnSent = itm.Sent
If blnSent = False Then
itm.DeleteAfterSubmit = True
Else
' do
End Sub
Please, try the next way:
Copy the next adapted code (instead of your code, or in a new standard module):
Option Explicit
Private itmevt As New CMailItemEvents
Public deleteFromDrafts As Boolean, boolContinue As Boolean
Sub TeamcenterWEBAccount()
Dim olMail As Outlook.MailItem, NewItem As Outlook.MailItem, boolDisplay As Boolean
Dim olApp As Outlook.Application, Fldr As MAPIFolder, olNs As NameSpace
Set olApp = New Outlook.Application
Set olNs = olApp.GetNamespace("MAPI")
Set Fldr = olNs.GetDefaultFolder(olFolderDrafts)
For Each olMail In Fldr.Items
If InStr(olMail.Subject, "New account") > 0 Then
On Error Resume Next 'for the case of inline response
Set NewItem = olMail.Copy
If Err.Number = -2147467259 Then
Err.Clear: On Error GoTo 0
olMail.Display: boolDisplay = True
For i = 1 To 1000: DoEvents: Next i 'just wait for the window to be displayed...
Set NewItem = olMail.Copy
End If
On Error GoTo 0
deleteFromDrafts = False: boolContinue = False 'initialize the boolean variables to wait for them in the loop
If Not boolDisplay Then olMail.Display
Set itmevt.itm = olMail
'wait for close event to be triggered...
Do While deleteFromDrafts = False And boolContinue = False
DoEvents
Loop
If deleteFromDrafts Then
If Not olMail Is Nothing Then olMail.Delete 'let only the copy...
End If
Exit Sub
End If
Next olMail
End Sub
Copy the next adapted code to replace the existing one in the used class:
Option Explicit
Public WithEvents itm As Outlook.MailItem
Private Sub itm_Close(Cancel As Boolean)
Dim blnSent As Boolean
On Error GoTo Ending 'for the case of mail sending, when itm looses its reference...
If blnSent = False Then
itm.DeleteAfterSubmit = True
deleteFromDrafts = True
Else
boolContinue = True
End If
Exit Sub
Ending:
boolContinue = True
End Sub
Tested, but not intensively...
Please, send some feedback after testing it in your specific environment.
First of all, iterating over all items in the folder is not really a good idea:
For Each olMail In Fldr.Items
If InStr(olMail.Subject, "New account") <> 0 Then
Instead, let the store provider do the job for you. The Find/FindNext or Restrict methods of the Items class allows getting items that correspond to your conditions, so you could iterate over items needed. 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
You may try handling the Close event of the Inspector class which is fired when the inspector associated with a Microsoft Outlook item is being closed.
But I think none of them can be helpful. You need to re-design the whole solution by tracking for new items in the folder. And if new items have a custom property which indicates whether to remove the item or not you can do the additional actions. In the item-level event it is impossible to delete the source item.
My changes in module:
Private itmevt As New CMailItemEvents
Public deleteFromDrafts As Boolean, boolContinue As Boolean, boolDisplay As Boolean
Private olMail As Outlook.MailItem, NewItem As Outlook.MailItem
Private olApp As Outlook.Application, olNs As NameSpace, Fldr As MAPIFolder
Sub TeamcenterWEBAccount()
AccountOrInstallation ("Nieuw TC11 VDL ETG Teamcenter WEB account")
End Sub
Sub AccountOrInstallation(ByVal SearchStr As String)
Set olApp = New Outlook.Application
Set olNs = olApp.GetNamespace("MAPI")
Set Fldr = olNs.GetDefaultFolder(olFolderDrafts)
For Each olMail In Fldr.Items
If InStr(olMail.Subject, SearchStr) > 0 Then
On Error Resume Next 'for the case of inline response
Set NewItem = olMail.Copy
If Err.Number = -2147467259 Then
Err.Clear: On Error GoTo 0
olMail.Display: boolDisplay = True
For i = 1 To 1000: DoEvents: Next i 'just wait for the window to be displayed...
Set NewItem = olMail.Copy
End If
On Error GoTo 0
deleteFromDrafts = False: boolContinue = False 'initialize the boolean variables to wait for them in the loop
If Not boolDisplay Then olMail.Display
Set itmevt.itm = olMail
'wait for close event to be triggered...
Do While deleteFromDrafts = False And boolContinue = False
DoEvents
Loop
If deleteFromDrafts Then
If Not olMail Is Nothing Then olMail.Delete 'let only the copy...
End If
Exit Sub
End If
Next olMail
End Sub

How do I check for "Test Email" in the subject?

I tried to set a rule in Outlook only to learn that rules are not case-sensitive.
I want if an email is received and the subject includes "Test Email" (like This is a Test Email), then check the body.
If the body contains the word NO, in capital letters (not a part of a word), then move the email to a specific folder.
I found the below script for incoming emails that contain NO in the body.
How do I first check for "Test Email" in the title?
Private WithEvents InboxItems As Outlook.Items
Private m_Rules As Variant
Sub Application_Startup()
Dim i As Long
i = -1: ReDim m_Rules(1000)
i = i + 1: m_Rules(i) = Array("NO", "No Folder")
ReDim Preserve m_Rules(i)
Set InboxItems = Application.Session.GetDefaultFolder(olFolderInbox).Items
End Sub
Private Sub InboxItems_ItemAdd(ByVal Item As Object)
Dim Folder As Outlook.MAPIFolder
Dim i As Long, Find As String
'Find = Item.Subject
Find = Item.Body
For i = 0 To UBound(m_Rules)
If InStr(1, Find, m_Rules(i)(0), vbBinaryCompare) Then
Set Folder = Application.Session.GetDefaultFolder(olFolderInbox)
Set Folder = Folder.Folders(m_Rules(i)(1))
Item.Move Folder
Exit For
End If
Next
End Sub
Here is a Regex search function which I use to filter received e-mail. Should be editable to what you desire
In ThisOutlookSession
Private Sub Application_NewMailEx(ByVal EntryIDCollection As String)
On Error Resume Next
Call RegExFilterRules(EntryIDCollection)
End Sub
In a module
Sub RegExFilterRules(ItemID As String)
Dim ThisNamespace As Outlook.NameSpace: Set ThisNamespace = Application.GetNamespace("MAPI")
Dim Inbox As Outlook.MAPIFolder: Set Inbox = ThisNamespace.GetDefaultFolder(olFolderInbox)
Dim Junk As Outlook.MAPIFolder: Set Junk = ThisNamespace.GetDefaultFolder(olFolderJunk)
Dim oMsg As Outlook.MailItem: Set oMsg = ThisNamespace.GetItemFromID(ItemID, Inbox.StoreID)
If Not oMsg Is Nothing And oMsg.Class = olMail Then
If FindPattern(oMsg.Subject, "^M\d+$") Then oMsg.Move Junk ' oMsg.Delete
End If
End Sub
Private Function FindPattern(Str As String, Pattern As String) As Boolean
' Requires Reference: Microsoft Scripting Runtime
Dim RegEx As Object: Set RegEx = CreateObject("vbscript.RegExp")
With RegEx
.Global = True
.IgnoreCase = True
.MultiLine = True
.Pattern = Pattern
FindPattern = .Test(Str)
End With
End Function

Items_ItemAdd(ByVal Item As Object) is not processing multiple items that come in at the same time

If only one email is sent at a time then my code works fine, otherwise, if multiple items come in at the same time then only one of the emails is processed and moved. Basically, my code is processing items as they come into outlook. And if the email is received as a distribution list then the email is sent to a sub folder based on the distribution list name and time of day.
Here's my code:
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 cusItem As Object)
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
Dim strEntryID As String
Dim objAddressentry As Outlook.AddressEntry
Dim objRecipient As Outlook.Recipient
Dim objDestFolder As Outlook.MAPIFolder
Dim objRecs As Outlook.Recipients
Dim i As Integer
If TypeName(cusItem) = "MailItem" Then
On Error GoTo ErrorHandler
Set objRecs = cusItem.Recipients
For i = 1 To objRecs.Count
Set objRecipient = objRecs.Item(i)
strEntryID = objRecipient.EntryID
Set objAddressentry = objNS.GetAddressEntryFromID(strEntryID)
If objAddressentry = "amazonselling" And TimeValue(Now()) >= TimeValue("08:00:00 AM") And TimeValue(Now()) <= TimeValue("05:00:00 PM") Then
Set objDestFolder = objNS.GetDefaultFolder(olFolderInbox).Folders("ryule")
cusItem.Move objDestFolder
Exit For
End If
Next
End If
ProgramExit:
Exit Sub
ErrorHandler:
MsgBox Err.Number & " - " & Err.Description & vbCrLf & "Click Ok to continue operations"
Resume ProgramExit
End Sub
Also, if I don't declare and set those variables twice then my code doesn't work as intended. Why is that and how could that be fixed?
The ItemAdd event is not fired when a large number of items are added to the folder at once (more than sixteen). This is a known issue when dealing with the Outlook object model. Instead, I'd suggest considering the NewMailEx event which is fired 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.
Anyway, it seems the problem is in your code, try to remove additional declarations from both methods:
Private WithEvents Items As Outlook.Items
Private objNS As Outlook.NameSpace
Private Sub Application_Startup()
Set objNS = Application.GetNamespace("MAPI")
Set Items = objNS.GetDefaultFolder(olFolderInbox).Items
End Sub
Private Sub Items_ItemAdd(ByVal cusItem As Object)
Dim strEntryID As String
Dim objAddressentry As Outlook.AddressEntry
Dim objRecipient As Outlook.Recipient
Dim objDestFolder As Outlook.MAPIFolder
Dim objRecs As Outlook.Recipients
Dim i As Integer
If TypeName(cusItem) = "MailItem" Then
On Error GoTo ErrorHandler
Set objRecs = cusItem.Recipients
For i = 1 To objRecs.Count
Set objRecipient = objRecs.Item(i)
strEntryID = objRecipient.EntryID
Set objAddressentry = objNS.GetAddressEntryFromID(strEntryID)
If objAddressentry = "amazonselling" And TimeValue(Now()) >= TimeValue("08:00:00 AM") And TimeValue(Now()) <= TimeValue("05:00:00 PM") Then
Set objDestFolder = objNS.GetDefaultFolder(olFolderInbox).Folders("ryule")
cusItem.Move objDestFolder
Exit For
End If
Next
End If
ProgramExit:
Exit Sub
ErrorHandler:
MsgBox Err.Number & " - " & Err.Description & vbCrLf & "Click Ok to continue operations"
Resume ProgramExit
End Sub

How to Automatically Move an Email to a Folder if it Contains 10 digits in the subject line

I would like to make it so if an email comes in with a phone number in the subject line (so 10 numerical digits) then the system automatically moves it to a folder called "Texting."
User Reidacus asked a very similar question here:
Move incoming mail to folders with RegEx in a rule
But I can't get it to work for me. When the email comes in it just sits in my inbox. I am very new the VBA and (sorry), I don't have a clue what I'm doing. Do I need to install anything special into my system to get this to work?
Here is my adapted code (note: in the real code I have my real email address)
Sub filter(Item As Outlook.MailItem)
Dim ns As Outlook.NameSpace
Dim MailDest As Outlook.Folder
Set ns = Application.GetNamespace("MAPI")
Set Reg1 = CreateObject("VBScript.RegExp")
Reg1.Global = True
Reg1.Pattern = "([\d][\d][\d][\d][\d][\d][\d][\d][\d][\d])"
If Reg1.Test(Item.Subject) Then
Set MailDest = ns.Folders("firstname.lastname#email.ca").Folders("Inbox").Folders("Texting")
Item.Move MailDest
End If
End Sub
In order for your Sub Filter to run everytime a new emails comes in, you need to add an "event listener", by adding the code below to the ThisOutlookSession module (this code is taken from home, here on SO : How do I trigger a macro to run after a new mail is received in Outlook? )
In order for this code to take affect, you must Restart Outlook.
ThisOutlookSession Module Code
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")
' get default local Inbox
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
If TypeName(item) = "MailItem" Then
Set Msg = item
' Call your custom-made Filter Sub
Call filterNewMail_TenDig(item)
End If
ProgramExit:
Exit Sub
ErrorHandler:
MsgBox Err.Number & " - " & Err.Description
Resume ProgramExit
End Sub
Now, you only need to make the following modifications to your Module code. Using ns.GetDefaultFolder(olFolderInbox) will get you the default "Inbox" folder for the current profile (read here at MSDN link ).
Sub filterNewMail_TenDig Code
Sub filterNewMail_TenDig(item As Outlook.MailItem)
Dim ns As Outlook.NameSpace
Dim MailDest As Outlook.Folder
Set ns = Outlook.Application.GetNamespace("MAPI")
Set reg1 = CreateObject("VBScript.RegExp")
With reg1
.Global = True
.IgnoreCase = True
.Pattern = "\d{10,10}" ' Match any set of 10 digits
End With
If reg1.Test(item.Subject) Then
Set MailDest = ns.GetDefaultFolder(olFolderInbox).Folders("Texting")
item.Move MailDest
End If
End Sub

Forward email based on subject line

I'm trying to forward emails from my company's Outlook to an email account outside of our company. I have been given the ok to do this.
I'd like to forward any email that contains "Excel Friday" in the subject line.
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")
' default local Inbox
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
If TypeName(Item) = "MailItem" Then
Set Msg = Item
If Msg.Subject = "Excel Friday" Then
Dim myMail As Outlook.MailItem
Set myMail = Msg.Reply
myMail.To = "xxxxxx#fakemail.com"
myMail.Display
End If
End If
ProgramExit:
Exit Sub
ErrorHandler:
MsgBox Err.Number & " - " & Err.Description
Resume ProgramExit
End Sub
I'd like to forward any email that contains "Excel Friday" in the subject line to another email address.
But in the code you check for the exact match of the subject line:
If Msg.Subject = "Excel Friday" Then
Instead you need to look for a substring. To find the position of a substring in a string, use Instr function.
If Instr(Msg.Subject, "Excel Friday") Then
Also I have noticed that you use the Reply method:
Set myMail = Msg.Reply
Use the Forward method instead:
Set myMail = Msg.Forward
And then use the Send method.
myMail.Recipients.Add "Eugene Astafiev"
myMail.Send
Be aware, the code is based on the ItemAdd event handler. This event is not fired when a large number of items are added to the folder at once (more than 16).
You can do this using a Run a Script rule
Sub ChangeSubjectForward(Item As Outlook.MailItem)
Item.Subject = "Test"
Item.Save
Set olForward = Item.Forward
olForward.Recipients.Add "Jasonfish11#domain.com"
olForward.Send
End Sub
If a vba you can run on all messages in a folder at any time.
Paste into ThisOutlookSession and run
Sub ChangeSubjectThenSend()
Dim olApp As Outlook.Application
Dim aItem As Object
Set olApp = CreateObject("Outlook.Application")
Set mail = olApp.ActiveExplorer.CurrentFolder
For Each aItem In mail.Items
aItem.Subject = "New Subject"
aItem.Save
Set olForward = aItem.Forward
olForward.Recipients.Add "Jasonfish11#domain.com"
olForward.Send
Next aItem
End Sub
source Link