Move/Copy Mail Item To Folder with ItemAdd event generates Error - vba

When I call Inbox_ItemAdd to make a copy of a Mail Item and then move the copy to a different folder, I get an error. The operation completes though.
When I debug the code it steps through without an error. It only errors when I remove the breakpoints. Finally, if I comment out:
moveMail.Move DestinationFolder
or
copied = MoveToFolder(copyMail, FolderName)
It creates volumes of copies in the originating folder. Its earliest entry point is from the ItemAdd event, so I'm wondering if
Set copyMail = olItem.Copy
results in kicking that event off again.
Here's my CopyToFolder and MoveToFolder functions:
Function MoveToFolder(olItem As Outlook.MailItem, FolderName As String) As Boolean
Dim objNS As Outlook.NameSpace
Dim Inbox As Outlook.Folder
Dim DestinationFolder As Outlook.Folder
Dim moveMail As Outlook.MailItem
Set objNS = Application.GetNamespace("MAPI")
Set DestinationFolder = objNS.Folders("MyMailBox#mailboxes.com").Folders(FolderName)
Set moveMail = olItem
moveMail.Move DestinationFolder
Set moveMail = Nothing
Set DestinationFolder = Nothing
Set Inbox = Nothing
Set objNS = Nothing
End Function
Function CopyToFolder(olItem As Outlook.MailItem, FolderName As String) As Boolean
Dim copyMail As Outlook.MailItem
Dim copied As Boolean
Set copyMail = olItem.Copy
copied = MoveToFolder(copyMail, FolderName)
CopyToFolder = copied
Set copyMail = Nothing
End Function
And I might call the CopyToFolder function by:
copyResult = CopyToFolder(olItem, "External")

Here is what MSDN states for the NewMailEx event:
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. Use this method with caution to minimize the impact on Outlook performance. However, depending on the setup on the client computer, after a new message arrives in the Inbox, processes like spam filtering and client rules that move the new message from the Inbox to another folder can occur asynchronously. You should not assume that after these events fire, you will always get a one-item increase in the number of items in the Inbox.
Looks like you have got some rules set up in Outlook. And these rules can be run against the item after the vent handler or asynchronously, i.e. when you try to call the Move method. Is it the case?
As a workaround you may consider getting the entry ID and try to get the received item after it's been processed by Outlook. Or just handle the ItemSend event instead.
Anyway, you may find the following series of articles helpful:
Outlook NewMail event unleashed: the challenge (NewMail, NewMailEx, ItemAdd)
Outlook NewMail event: solution options
Outlook NewMail event and Extended MAPI: C# example
Outlook NewMail unleashed: writing a working solution (C# example)

Related

Trigger macro on email to specific folder

Error: Object not Found.
MyEmailAddress has a folder called CL and when there is something there, I want a macro called "InsertData" to run.
Dim E_flge As Byte
Private Sub Application_NewMailEx(ByVal EntryIDCollection As String)
Dim NS As Outlook.NameSpace
Dim MyMail As Object
Set NS = Application.GetNamespace("MAPI")
Set MyMail = NS.GetItemFromID(EntryIDCollection)
E_flge = 0
If MyMail.Class = olMail Then
If MyMail.Parent.Parent = "MyEmailAddress" Then
InsertData 'Macro I am trying to call
End If
End If
End Sub
I pretty sure you need to have a actually "Call" the macro
Call InsertData
The object not found may be in the macro itself. Perhaps you should post that
"The NewMailEx event fires when a new message arrives in the Inbox..." https://msdn.microsoft.com/en-us/library/office/ff863686.aspx"
This is the default Inbox. You likely want to reference a non-default Inbox so you cannot use NewMailEx.
Try ItemAdd along with Get reference to additional Inbox

Getting email body using vba code

I am trying to get the email header and body inside my email in outlook using VBA. I am using the Application_NewMail() event handler to process that new mail has arrived, but I cannot figure out how to get the header and body from there.
This is the code that I have inside the Application_NewMail() event handler:
Private WithEvents myOlItems As Outlook.Items
Private Sub Application_NewMail()
Dim olApp As Outlook.Application
Dim oNS As NameSpace
Dim oFolder As MAPIFolder
Dim oNewMail As MailItem
Set olApp = Outlook.Application
Set oNS = GetNamespace("MAPI")
Set oFolder = oNS.GetDefaultFolder(olFolderInbox)
Set oNewMail = oFolder.Items.GetFirst
'This is the string that hold the mail body.
Dim mailBody As String
Dim mailArg() As String
MsgBox "New Mail!"
End Sub
This function is firing properly once I receive emails. I successfully get the messagebox to pop up. But I want to be able to read the mail body and header to insert into a database.
The actual database side of it I know how to do, but I am unsure how to get the header and body from the email. I have tried something like this:
Set olItem = ActiveExplorer.Selection.Item(1)
mailBody = oNewMail.Body
mailArg = Split(mailBody, vbLf)
'Check to see what is inside the body. We need to say Tank X: Y
MsgBox "This is line one " & mailArg(0) & "This is line two " & mailArg(1)
And I receive the error: Object variable or With block variable not set
Any help will be greatly appreciated.
You need to handle 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 EntryIDsCollection string contains the Entry ID that corresponds to that item.
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.
The Outlook object model provides three main ways for working with item bodies:
Body.
HTMLBody.
The Word editor. The WordEditor property of the Inspector class returns an instance of the Word Document which represents the message body. So, you can use the Word object model do whatever you need with the message body.
Finally, you can use the PropertyAccessor object (see the corresponding property of the MailItem class) to read the "PR_TRANSPORT_MESSAGE_HEADERS" property value.
propertyAccessor.GetProperty("http://schemas.microsoft.com/mapi/proptag/0x007D001E")

How I can run macro automatically with new email arrives in outlook

Am very new to VBScript and macro . I have a vbscript which will create tickets for email's but I need to run this script manually every time .To make it automation I have mapped my macro to the "run a script" script rule in Outlook but when the rule runs it is not fetching the data in the mail which is arrived .It's creating tickets with previous email always .
I have gone through so many VBscripts but none worked to convert the mail that received in to ticket.
If any one faced similar type of issue please let me know the complete solution.
Dim olApp As outlook.Application
Dim objNS As outlook.NameSpace
Dim objSourceFolder As outlook.MAPIFolder
Dim objDestFolder As outlook.MAPIFolder
Dim Msg As outlook.MailItem
Set olApp = outlook.Application
Set objNS = olApp.GetNamespace("MAPI")
Set objSourceFolder = objNS.GetDefaultFolder(olFolderInbox)
Set objDestFolder = objSourceFolder.Folders("Termination")
Set Msg = objDestFolder.Items.GetLast
Set sh = CreateObject("Shell.Application")
Set ie = CreateObject("InternetExplorer.Application")
LocationURL = "Ticket URL” & Msg.EntryID"
ie.Navigate (LocationURL)
ie.Visible = True
With ie.Document
.getElementById("details").Value = Msg.Body
.getElementById("short_description").Value = Msg.Subject
.getElementById("requester_login").Value = "premchand"
End With
When you run a macro from a rule it typically has an argument to which the item triggering the rule gets passed: you do not have to navigate through the Inbox to find the item.
Public Sub DoSomething(Item As Outlook.MailItem)
'code which acts on "Item"
End Sub
There are several ways for handling incoming emails:
The NewMailEx event of the Application class which is fired when a new item is received in the Inbox. This event is not available in Microsoft Visual Basic Scripting Edition (VBScript).
The ItemAdd event of the Items class is fired when one or more items are added to the specified collection. So, you can subscribe to the Inbox folder to see new items. Be aware, this event does not run when a large number of items are added to the folder at once. This event is not available in Microsoft Visual Basic Scripting Edition (VBScript).
Assign a macro VBA sub to the rule in Outlook. In that case the incoming mail item is passed as a parameter to the sub as Tim showed.

how to clear outbox with vba in outlook, still got one outgoing email

I want to "send" a message to specific recipient but do not want to deliver. The message is in the outbox but I want to delete it immediately. When I use the command delete it says it was deleted before sending. I do not want popups and also there is an alert when exiting Outlook that there are still unsent messages. How to clear outbox?
Private Sub Application_ItemSend(ByVal item As Object, Cancel As Boolean)
Dim outApp As Outlook.Application
Dim deletedFolder As Outlook.MAPIFolder
Dim entryID As String
Set outApp = CreateObject("outlook.application")
Set deletedFolder =outApp.GetNamespace("MAPI").GetDefaultFolder(olFolderOutbox)
If item.To = "example#mail.com" Then
item.DeferredDeliveryTime = DateAdd("y", 99999, Now)
End If
Set deletedFolder = outApp.GetNamespace("MAPI").GetDefaultFolder(olFolderOutbox)
If deletedFolder.Items.Count >= 0 Then
For i = 1 To deletedFolder.Items.Count
deletedFolder.Items(1).Delete
Next i
End If
End Sub
The Outbook folder contains yet unsent messages. It is definitely not the right time and place for deleting items because they were not sent. Instead, I'd suggest handling the ItemSend event and adding a user property (i.e. marker which can tell you later whether you need to delete that message or not), see UserProperties property of the MailItem class for more information. For example:
Set myUserProperty = myItem.UserProperties _
.Add("YourDetails", olText)
myUserProperty.Value = "Delete"
Then in the ItemAdd event handler of the Sent Items folder you can check out the user defined property value and delete the sent message if required. Be aware, the Sent Items folder is set as a target folder by default for sent items. But you can set a custom folder programmatically, see the SaveSentMessageFolder property - a Folder object that represents the folder in which a copy of the e-mail message will be saved after being sent.

Call Outlook procedure using VBScript

I have a procedure in Outlook that sends all the saved messages in Drafts folder.
Below is the code:
Public Sub SendMail()
Dim olApp As Outlook.Application
Dim olNS As Outlook.NameSpace
Dim olFolder As Outlook.MAPIFolder
Dim olDraft As Outlook.MAPIFolder
Dim strfoldername As String
Dim i As Integer
Set olApp = Outlook.Application
Set olNS = olApp.GetNamespace("MAPI")
Set olFolder = olNS.GetDefaultFolder(olFolderInbox)
strfoldername = olFolder.Parent
Set olDraft = olNS.Folders(strfoldername).Folders("Drafts")
If olDraft.Items.Count <> 0 Then
For i = olDraft.Items.Count To 1 Step -1
olDraft.Items.Item(i).Send
Next
End If
End Sub
Above code works fine.
Question:
I want to use Task Scheduler to fire this procedure as a specified time.
1. Where will I put the procedure in Outlook, Module or ThisOutlookSession?
2. I am not good in vbscript so I also don't know how to code it to call the Outlook Procedure. I've done calling Excel Procedure but Outlook doesn't support .Run property.
So this doesn't work:
Dim olApp
Set olApp = CreateObject("Outlook.Application")
olApp.Run "ProcedureName"
Set olApp = Nothing
I've also read about the Session.Logon like this:
Dim olApp
Set olApp = CreateObject("Outlook.Application")
olApp.Session.Logon
olApp.ProcedureName
Set olApp = Nothing
But it throws up error saying object ProcedureName is not supported.
Hope somebody can shed some light.
SOLUTION:
Ok, I've figured out 2 work around to Avoid or get pass this pop-up.
1st one: is as KazJaw Pointed out.
Assuming you have another program (eg. Excel, VBScript) which includes sending of mail via Outlook in the procedure.
Instead of using .Send, just .Save the mail.
It will be saved in the Outlook's Draft folder.
Then using below code, send the draft which fires using Outlook Task Reminder.
Option Explicit
Private WithEvents my_reminder As Outlook.Reminders
Private Sub Application_Reminder(ByVal Item As Object)
Dim myitem As TaskItem
If Item.Class = olTask Then 'This works the same as the next line but i prefer it since it automatically provides you the different item classes.
'If TypeName(Item) = "TaskItem" Then
Set my_reminder = Outlook.Reminders
Set myitem = Item
If myitem.Subject = "Send Draft" Then
Call SendMail
End If
End If
End Sub
Private Sub my_reminder_BeforeReminderShow(Cancel As Boolean)
Cancel = True
Set my_reminder = Nothing
End Sub
Above code fires when Task Reminder shows with a subject "Send Draft".
But, we don't want it showing since the whole point is just to call the SendMail procedure.
So we added a procedure that Cancels the display of reminder which is of olTask class or TaskItem Type.
This requires that Outlook is running of course.
You can keep it running 24 hours as i did or, create a VBscript that opens it to be scheduled via Task Scheduler.
2nd one: is to use API to programatically click on Allow button when the security pop-up appears.
Credits to SiddarthRout for the help.
Here is the LINK which will help you programmatically click on the Allow button.
Of course you have to tweak it a bit.
Tried & Tested!
Assuming that you have Outlook Application always running (according to comment below your question) you can do what you need in the following steps:
add a new task in Outlook, set subject to: "run macro YourMacroName" and set time (plus cycles) when your macro should start.
go to VBA Editor, open ThisOutlookSession module and add the following code inside (plus see the comments inside the code):
Private Sub Application_Reminder(ByVal Item As Object)
If TypeName(Item) = "TaskItem" Then
Dim myItem As TaskItem
Set myItem = Item
If myItem.Subject = "run macro YourMacroName" Then
Call YourMacroName '...your macro name here
End If
End If
End Sub
Where will I put the procedure in Outlook, Module or ThisOutlookSession?
Neither. Paste the below code in a Text File and save it as a .VBS file. Then call this VBS file from the Task Scheduler as shown HERE
Dim olApp, olNS, olFolder, olDraft, strfoldername, i
Set olApp = GetObject(, "Outlook.Application")
Set olNS = olApp.GetNamespace("MAPI")
Set olFolder = olNS.GetDefaultFolder(6)
strfoldername = olFolder.Parent
Set olDraft = olNS.Folders(strfoldername).Folders("Drafts")
If olDraft.Items.Count <> 0 Then
For i = olDraft.Items.Count To 1 Step -1
olDraft.Items.Item(i).Send
Next
End If
If you are using Outlook 2007 or newer I have found you can easily eliminate the security pop up you mentioned above when running your script by doing the following:
In Outlook 2007 Trust Center, go to Macro Security - Select "No security Check for macros"
In Outlook 2007 Trust Center, go to Programatic Access - Select "Never warn me abous suspicious activity.
Of course that technically leaves you open to the remote possibility for someone to email you some malicious email script or something of that nature I assume. I trust my company has that managed though and this works for me. I can use VBS scripts in Outlook, Access, Excel to send emails with no security pop up.
Another Option:
If you don't want to do that, another option that has worked well for me prior to this is here:
http://www.dimastr.com/redemption/objects.htm
Basically a dll redirect that does not include the popup. It leaves your other default security in place and you write \ call your VBA for it and send mail without the secutity pop-ups.