Outlook VBA \ Macro conversion to Add-in - vba

I'm in the process of converting some Outlook VBA \ Macros into add-ins.
So far I'm not having a lot of luck piping this code over to VS2015 w\Office Dev Tools.
I've created a ribbon \ group \ buttons \ I can see it in Outlook and everything looks good but I'm receiving an error.
--ORIGINAL MACRO--
Sub Request()
Set myOlApp = CreateObject("Outlook.Application")
Set myNameSpace = myOlApp.Application.GetNamespace("MAPI")
Set objFolder = Session.GetDefaultFolder(olPublicFoldersAllPublicFolders).Folders("Shared Documents")
Set myItem = objFolder.Items.Add("IPM.Note.Request")
myItem.Display
End Sub
I'm seeing that Set is no longer permitted so they've all been defined.
This particular line seems to be the problem.
Session and\or GetDefaultFolder are returning Null and causing a runtime exception.
Error -- "System.NullReferenceException" --
objFolder = Session.GetDefaultFolder(olPublicFoldersAllPublicFolders).Folders("Shared Documents")
The suggestion from VS is to use the Sub "New" along with a few others that don't seem applicable.
A little help please. :-)
Seems that I'm getting a mix of programming types mixed up from the VS error resolution suggestions.
Thank you. -Chris

Alrighty, it's working meow.
Found this handy dandy webpage in case someone needs some pointers:
https://support.microsoft.com/en-us/kb/313800
When you create a project for Outlook Add-ins it's being coded in VB.Net
Thank you DanL for the input, it got me thinking and searching again.
Private Sub Button1_Click(sender As Object, e As RibbonControlEventArgs) Handles Button1.Click
Dim objOutlook As Outlook._Application
objOutlook = New Outlook.Application()
Dim objNS As Outlook._NameSpace = objOutlook.Session
Dim objFolder As Outlook.MAPIFolder =
objNS.GetDefaultFolder(Outlook.OlDefaultFolders.olPublicFoldersAllPublicFolders).Folders("Shared Documents")
Dim myItem = objFolder.Items.Add("IPM.Note.CustomFormName")
myItem.Display()
End Sub

Related

Call outlook macro from code

I get an error when I run the InvokeMember method below. The error is UNKNOWN NAME. I have checked the spelling and it is correct. In Outlook I have Enable Macros in the trust center. Is there anything I might be missing to get this working? Thanks
VB code:
olApp.GetType().InvokeMember("Run", Reflection.BindingFlags.Default Or
Reflection.BindingFlags.InvokeMember,
Nothing, olApp, New Object() {"nameOfMacro"})
Research
Well, it seems InvokeMember will not work. The answer is to make the code as you would in the macro and run that. Example:
Private Sub MoveAttachmentToFolder()
Dim olNs = olApp.GetNamespace("MAPI")
Dim subFolderA = olNs.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox).Parent.Folders("subFolderA")
Dim subFolderB = olNs.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox).Parent.Folders("subFolderB")
For Each mi As Outlook.MailItem In subFolderA.Items
If mi.Attachments.Count = 1 Then
'remember interops use 1 based arrays not zero
Dim fileName As String = "some path" & mi.Attachments(1).FileName
mi.Attachments(1).SaveAsFile(fileName)
mi.Move(subFolderB)
End If
Next
End Sub

Excel VBA: Stops Working at Outlook Email Creation Subroutine

I asked this question the other day and thought I found the answer, but now Excel keeps going into it's 'Not Responding' mode. My issue is that the program runs fine on some computers, but bombs out on others.
Background:
This program gets run after the user fills in an Excel form and clicks submit. The program validates the data, manipulates the data, creates an email via Outlook, and finally saves and closes the document.
The program gets run on many co-workers' computers at work. We all run on Windows 7, Office 2013, but some of us have different laptops (HP, Dell, etc.)
Here is the call to the subroutine, which is the line of code that excel starts to 'Not Respond' - FYI, this is NOT a debugging stop:
Call EmailApprovalP1(GeneralSection, ItemSection, VendorSection, MarketSection, Part1Section, wbLog, wbPCD, resubmission)
Here is the beginning of the subroutine being called:
Public Sub EmailApprovalP1(ByRef GeneralSection As Object, ByRef ItemSection As Object, ByRef VendorSection As Object, ByRef MarketSection As Object, ByRef Part1Section As Object, ByRef wbLog As Workbook, ByRef wbPCD As Workbook, ByRef resubmission As Boolean)
'Declare In Memory
Dim i As Integer
Dim toEmail As String
Dim subject As String
Dim body As String
Dim OL As New Outlook.Application
Dim olMail As Outlook.MailItem
Set olMail = OL.CreateItem(olMailItem)
If I stop the code on Call EmailApprovalP1() then press F8, Excel stops responding. Does anyone have any ideas on what could be causing this?
UPDATED 2-3-15
CODE THAT WORKED ON ALL COMPUTERS
Dim OL As Object
Set OL = CreateObject("Outlook.Application")
Dim olMail As Object
Set olMail = OL.CreateItem(olMailItem)
Use CreateObject instead of New. New is known to cause some instability issues.
Dim OL As Outlook.Application
Set OL = CreateObject("Outlook.Application")
First of all, make sure that you added a reference to Outlook before running the code. You need to do that on each PC where you have to get the code running. The How to automate Outlook from another program article describes all the required steps for automating Outlook from another applications.
If it doesn't help, try to Step Into (F8) the function and find the exact line of code which causes the issue.
Declaring in Memory as Object instead of Outlook.Application made the difference. Thanks for pointing me in the right direction #Eugene & #Jeanno!
Below is the code that worked:
Dim OL As Object
Set OL = CreateObject("Outlook.Application")
Dim olMail As Object
Set olMail = OL.CreateItem(olMailItem)

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.

Outlook VBA troubleshooting

I have the following block of VBA code, which should create a popup box with the first name for each contact in my default folder.
Sub DeleteaContact()
Dim myOutlook As Outlook.Application
Dim myInformation As NameSpace
Dim myContacts As Items
Dim myItems As ContactItem
Set myOutlook = CreateObject("Outlook.Application")
Set myInformation = myOutlook.GetNamespace("MAPI")
Set myContacts = myInformation.GetDefaultFolder(olFolderContacts).Items
For Each myItems In myContacts
MsgBox (myItems.FirstName)
Next
End Sub
For some reason I am getting a sporadic type mismatch error at the end of the loop.
Can anyone shed some light on this subject as to why?
Folders can store more than just the data type you'd expect. Change myItems to
Dim myItems As Object
and change the message box to
Debug.Print TypeName(myItems)
Then check the Immediate Window (Ctl+G) to see if any of the items are not ContactItem. If you determine you have something in there that's not a contact, you simply need to test for it. Keep myItems as Object, but use code like
If TypeName(myItems) = "ContactItem" Then
MsgBox myItems.FirstName
End If
Generally, I leave my variables typed as the specific item (e.g. ContactItem) while I'm writing the code and then convert them all to Object when I'm done. That way you get the benefit of Intellisense while you're coding.
Try changing:
MsgBox (myItems.FirstName)
to:
MsgBox myItems.FirstName
as VBA doesn't like unnecessary parentheses

When is a MailItem not a MailItem? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I have written a message handler function in Outlook's Visual Basic (we're using Outlook 2003 and Exchange Server) to help me sort out incoming email.
It is working for me, except sometimes the rule fails and Outlook deactivates it.
Then I turn the rule back on and manually run it on my Inbox to catch up. The rule spontaneously fails and deactivates several times a day.
I would love to fix this once and for all.
This code showed me the different TypeNames that were in my Inbox:
Public Sub GetTypeNamesInbox()
Dim myOlItems As Outlook.Items
Set myOlItems = application.GetNamespace("MAPI").GetDefaultFolder(olFolderInbox).Items
Dim msg As Object
For Each msg In myOlItems
Debug.Print TypeName(msg)
'emails are typename MailItem
'Meeting responses are typename MeetingItem
'Delivery receipts are typename ReportItem
Next msg
End Sub
HTH
I use the following VBA code snippet in other Office Applications, where the Outlook Library is directly referenced.
' Outlook Variables
Dim objOutlook As Outlook.Application: Set objOutlook = New Outlook.Application
Dim objNameSpace As Outlook.NameSpace: Set objNameSpace = objOutlook.GetNamespace("MAPI")
Dim objFolder As MAPIFolder: Set objFolder = objNameSpace.PickFolder()
Dim objMailItem As Outlook.MailItem
Dim iCounter As Integer: iCounter = objFolder.Items.Count
Dim i As Integer
For i = iCounter To 1 Step -1
If TypeOf objFolder.Items(i) Is MailItem Then
Set objMailItem = objFolder.Items(i)
With objMailItem
etc.
have written a message handler function in Outlook's Visual Basic (we're using Outlook 2003 and Exchange Server) to help me sort out incoming email. It is working for me, except sometimes the rule fails and Outlook deactivates it. Then I turn the rule back on and manually run it on my Inbox to catch up. The rule spontaneously fails and deactivates several times a day. I would love to fix this once and for all.
Here is the code stripped of the functionality, but giving you an idea of how it looks:
Public WithEvents myOlItems As Outlook.Items
Public Sub Application_Startup()
' Reference the items in the Inbox. Because myOlItems is declared
' "WithEvents" the ItemAdd event will fire below.
' Set myOlItems = Outlook.Session.GetDefaultFolder(olFolderInbox).Items
Set myOlItems = Application.GetNamespace("MAPI").GetDefaultFolder(olFolderInbox).Items
End Sub
Private Sub myOlItems_ItemAdd(ByVal Item As Object)
On Error Resume Next
If TypeName(Item) = "MailItem" Then
MyMessageHandler Item
End If
End Sub
Public Sub MyMessageHandler(ByRef Item As MailItem)
Dim strSender As String
Dim strSubject As String
If TypeName(Item) <> "MailItem" Then
Exit Sub
End If
strSender = LCase(Item.SenderEmailAddress)
strSubject = Item.Subject
rem do stuff
rem do stuff
rem do stuff
End Sub
One error I get is "Type Mismatch" calling MyMessageHandler where VB complains that Item is not a MailItem. Okay, but TypeName(Item) returns "MailItem", so how come Item is not a MailItem?
Another one I get is where an email with an empty subject comes along. The line
strSubject = Item.Subject
gives me an error. I know Item.Subject should be blank, but why is that an error?
Thanks.
My memory is somewhat cloudy on this, but I believe that a MailItem is not a MailItem when it is something like a read receipt. (Unfortunately, the VBA code that demonstrated this was written at another job and isn't around now.)
I also had code written to process incoming messages, probably for the same reason you did (too many rules for Exchange, or rules too complex for the Rules Wizard), and seem to recall running into the same problem you have, that some items seemed to be from a different type even though I was catching them with something like what you wrote.
I'll see if I can produce a specific example if it will help.
There are many types of items that can be seen in the default Inbox.
In the called procedure, assign the incoming item to an Object type variable. Then use TypeOf or TypeName to determine if it is a MailItem. Only then should your code perform actions that apply to emails.
i.e.
Dim obj As Object
If TypeName(obj) = "MailItem" Then
' your code for mail items here
End If
Dim objInboxFolder As MAPIFolder
Dim oItem As MailItem
Set objInboxFolder = GetNamespace("MAPI").GetDefaultFolder(olFolderInbox)
For Each Item In objInboxFolder.Items
If TypeName(Item) = "MailItem" Then
Set oItem = Item
next
why not use a simple error handler for the code? Seriously. You could write an error for each read of a property or object that seems to fail. Then have it Resume no matter what. No need for complex error handling. Think of a test that shows an empty subject. Since you don't know what value it will return, if any, and it seems to error on an empty or blank subject, you need to picture it as a simple test with a possible error. Run the test as an if statement (one in which you will get an error anyway), and have the program resume on error.
On Error Resume Next
If object.subject = Null 'produces an error when subject is null, otherwise allows a good read
strSubject = "" 'sets the subject grab string to a null or empty string as a string
Else
strSubject = object.subject 'Sets the subject grab string to the subject of the message\item
End If