Send/Receive in Outlook via code - vba

If I create an Outlook 2010 object In Excel VBA using
Sub CreateOL()
On Error Resume Next
Set myOlApp = GetObject(, "Outlook.Application")
If Err.Number = 429 Then
Set myOlApp = CreateObject("Outlook.Application")
End If
On Error GoTo 0
End Sub
Is it possible to force myOLAPP to send/receive. Please can somebody advise how it's done?
I've tried the following but it's not working for me.
Set nsp = myOlApp.GetNamespace("MAPI")
Set sycs = nsp.SyncObjects
For i = 1 To sycs.Count
Set syc = sycs.Item(i)
syc.Start
Next
Also, how do I make myOlApp visible? myOlApp.Visible = True and myOlApp.Application.Visible = True doesn't work
Thank you

Which Outlook version are you using? I tested this with Outlook 2010 and it works.
NOTE: I have not done any error handling. I am sure you can take care of that.
Public Sub Sample()
Dim oLook As Object
Dim nsp As Object, objSyncs As Object, objSync As Object
Dim i As Long
Set oLook = GetObject(, "Outlook.Application")
Set nsp = oLook.GetNamespace("MAPI")
Set objSyncs = nsp.SyncObjects
For i = 1 To objSyncs.Count
Set objSync = objSyncs.Item(i)
objSync.Start
Next
End Sub
MS Outlook has 2 types of windows
Explorer for Folders and
Inspector for individual items.
If you want to show a particular folder, you can start the Explorer for it then either use .Activate or .Display. An alternative would be to use MAPIFolder.Display method as well.

Related

How to close Outlook using VBA from MS Access

I want to close Outlook before creating an appointment. My appointment will only get created when Outlook is closed. So I want to close/quit Outlook so the user will not have to. How do I close Outlook using VBA from MS Access?
Private Sub Command0_Click()
Dim olApp As Outlook.Application
Dim olApt As AppointmentItem
Set olApp = New Outlook.Application
Set olApt = olApp.CreateItem(olAppointmentItem)
With olApt
End With
End If
Set olApt = Nothing
Set olApp = Nothing
ExitProc:
Exit Sub
Call olApt.Quit method.
You might want to check that Application.Explorers.Count = 0 and Application.Inspectors.Count = 0 to make sure you don't kill the instance the user is working in.

oultlook vba loop over inbox, not bulk scan

We have a shared mailbox, and the alerts folder gets filled with alerts. Thousands of them - most from start of day and end of day. New alerts in the middle of the day might actually be something that we need look at.
Noone ever bulk marks the folder as read in the morning, because it takes too long - you can't highlight the who mailbox and click "mark as unread". The onely way to mark the emails is by highlighting a few hundred at a time - which takes along time manually.
I made thsi script because it will automagically mark the emails in the "alerts' folder. However, it seems to go after the whole folder at the same time. The script ist eh equivalent of highlightimg the whole folder, and marking a bulk delete. It takes to long and locks up the shared email box. I would like something that would start at the bottom of the folder, cycle through each email, and if unread, mark the email unread. pause for a second, then the next one.
Is that possible?
Sub Test2()
Dim objInbox As Outlook.MAPIFolder
Dim objOutlook As Object, objnSpace As Object, objMessage As Object
Dim objSubfolder As Outlook.MAPIFolder
Set objOutlook = CreateObject("Outlook.Application")
Set objnSpace = objOutlook.GetNamespace("MAPI")
Set objInbox = objnSpace.GetDefaultFolder(olFolderInbox)
Set objSubfolder = objInbox.Folders.Item("_ALERTS")
For Each objMessage In objSubfolder.Items
objMessage.UnRead = False
Next
Set objOutlook = Nothing
Set objnSpace = Nothing
Set objInbox = Nothing
Set objSubfolder = Nothing
End Sub
You can create a code in Outlook which get triggers when new Email entered in a target folder.
Public WithEvents objMails As Outlook.Items
Private Sub Application_Startup()
Set objMails = Outlook.Application.Session.GetDefaultFolder(olFolderInbox).Folders("_ALERTS").Items
End Sub
Private Sub objMails_ItemAdd(ByVal Item As Object)
'Do more stuff
End Sub
which will avoid looping through all the emails at a time
You could use Restrict to limit the items to be processed.
Option Explicit
Sub Test2()
Dim objInbox As Folder
Dim objnSpace As namespace
Dim objSubfolder As Folder
dim unreadItems As items
dim unreaditemsCount as long
Set objnSpace = GetNamespace("MAPI")
Set objInbox = objnSpace.GetDefaultFolder(olFolderInbox)
Set objSubfolder = objInbox.Folders.Item("_ALERTS")
set unreadItems = objSubfolder.Items.Restrict("[UnRead] = True")
unreaditemsCount = unreadItems.Count
If unreaditemsCount > 0 Then
' Reverse loop when changing the number of items in the collection
For i = unreaditemsCount to 1
unreadItems(i).UnRead = False
Next
end if
Set objInbox = Nothing
Set objnSpace = Nothing
Set objSubfolder = Nothing
Set unreadItems = Nothing
End Sub

How to automate saving an inbox message to a folder when closing after reading - Outlook 2010 VBA

I want to keep this in VBA. I'm seeking info on how to work around the following issue.
I get this error:
The item's properties and methods cannot be used inside this event procedure. MS has stopped people being able to use the .Close, .Move and .Delete methods in the Inspector_Close event.
I've seen suggestions to use threading to run a delayed macro, but can't find help on this, and suspect it may not be available in VBA.
My code is as follows:
Private Sub objInspector_Close()
Dim objNS As NameSpace
Dim objFolder As MAPIFolder
'On Error Resume Next
Set objNS = Application.Session
If Not mailSent Then
If objInspector.CurrentItem.Class = olMail Then
'Mail inspector is closing
If objInspector.CurrentItem.Parent = "Inbox" Then
Set objFolder = objNS.PickFolder
If Not objFolder Is Nothing And IsInDefaultStore(objFolder) _
And objFolder.DefaultItemType = olMailItem Then
Set objInspector.CurrentItem.Move = objFolder
End If
End If
End If
Else
mailSent = False
End If
Set objFolder = Nothing
Set objNS = Nothing
End Sub
The global mailSent Boolean is there to prevent this event code executing when I send / close an email.
The error occurs on Set objInspector.CurrentItem.Move = objFolder.
Is there a way for me to delay this until the event ends or perhaps to set some flags on the email item and then run a macro over all emails in my inbox later to move them to folders.
I work on multiple projects and maintain multiple email folders and am looking for ways to automate my email management. I've seen other pages where folder names are derived from email subjects but I don't want to do that.
Thanks for your help.
You may consider adding a user property which can mark the message for moving etc. Then you can use the Find/FindNext or Restrict methods for searching marked items. You can 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
Also you can use the GetTable method of the Folder class which obtains a Table object that contains items filtered by Filter.
As you probably know the Outlook object model can't be used from another threads. You need to use a low-level API - Extended MAPI which supports secondary threads. Or any other third-party wrappers around that API, for example - Redemption.
You could abandon the idea of using a trigger and move "manually"
Option Explicit
Private Sub MoveCurrentItem()
Dim objNS As Namespace
Dim objFolder As folder
Dim currItem As Object
Dim uPrompt As String
Set objNS = Application.Session
On Error Resume Next
Set currItem = ActiveInspector.currentItem
On Error GoTo 0
If currItem Is Nothing Then GoTo ExitRoutine
If currItem.Class = olMail Then
If currItem.Sent Then ' reading not composing
If currItem.Parent = "Inbox" Then
Set objFolder = objNS.PickFolder
If Not objFolder Is Nothing And IsInDefaultStore(objFolder) _
And objFolder.DefaultItemType = olMailItem Then
currItem.Move objFolder
End If
End If
End If
End If
ExitRoutine:
Set currItem = Nothing
Set objFolder = Nothing
Set objNS = Nothing
End Sub

For Each to Iterate through a List of Outlook Calendar Items

I want to change the time zone of all items in an Outlook 2010 calendar.
I am confused as to how one would work with the items of a collection as they are iterated in the loop. My main background is in Java, and as I understand loops there a single variable is used as a dummy variable that will take the value of all items in the collection, in turn. No special assignment is usually required for such FOR loops. Do you need to manually advance the variable in some way so as to keep the loop going?
Here is my code:
Public Sub TZFix()
Dim oAppointmentItem As Outlook.AppointmentItem
Dim tzs As Outlook.TimeZones
Dim tzCentral As Outlook.TimeZone
Dim oAppointments As Object
Dim oNS As Outlook.NameSpace
Set oNS = oOutlook.GetNamespace("MAPI")
Set oAppointments = oNS.GetDefaultFolder(olFolderCalendar)
Set tzs = Application.TimeZones
Set tzCentral = tzs("Central Standard Time")
For Each oAppointmentItem In oAppointments.Items
Set oAppointmentItem.StartTimeZone = tzCentral
Set oAppointmentItem.EndTimeZone = tzCentral
Next
End Sub
I believe that there is an issue with variable assignment within the loop, as I get an Error 91: Object Variable or With block variable not set error whenever I run it.
oOutlook is never assigned to and is therefore Nothing. You probably meant to set it to Application.
Also, setting local variables to Nothing in the end is redundant, remove that.
I also had this problem in my Script. For me the solution was setting the Macro-Security-Settings to the lowest and ran it again and it worked.
Maybe it's worth giving it a try!
I made the code working with few changes of your code. This is worked:
Public Sub TZ_change_to_Hawaii()
''''Changing the selected appointments' time zones to Hawaii
Dim tzs As Outlook.TimeZones
Dim tzCentral As Outlook.TimeZone
Set tzs = Application.TimeZones
Set tzCentral = tzs("Hawaiian Standard Time")
Dim objOL As Outlook.Application
Dim objSelection As Outlook.Selection
Dim objItem As Object
Set objOL = Outlook.Application
Set objSelection = objOL.ActiveExplorer.Selection
For Each objItem In objSelection
Set objItem.StartTimeZone = tzCentral
Set objItem.EndTimeZone = tzCentral
objItem.Save
Next
End Sub

Determining whether an existing Outlook instance is open

After reading how to use automation to send a message, I'm unclear of whether it's possible to avoid opening a new instance of Outlook if I already have one opened. If so, I'm unsure of how to search for examples determining whether an existing Outlook instance is open.
-----Including the suggestion--------
I have the following snippet, but I found that I can't create the instance properly. I'm basically following this example. I'm either getting this screenshot, or the error of "User-defined type not defined." Any suggestions?
Sub Example()
'Dim w As Outlook.Application
Const ERR_APP_NOTRUNNING As Long = 429
On Error Resume Next
' Handle Microsoft outlook
Set w = GetObject(, "Outlook.Application")
If Err = ERR_APP_NOTRUNNING Then
'Set w = New Outlook.Application
Set w = CreateObject("Outlook.Application")
End If
End Sub
I know this question has been answered, but I thought I'd add that applications like Outlook (and I believe PowerPoint as well) are single-instance applications -- there is no need to determine if Outlook is already open because you can only have one copy of Outlook running.
http://msdn.microsoft.com/en-us/library/aa164542(v=office.10).aspx
If you need to instantiate Outlook, simply use CreateObject to create the instance; if Outlook is already running, your object reference will point to the existing instance. If not, you will create the class. Binding (late or early) is irrelevant.
For example, let's say Outlook isn't running. We can use this code to create the instance:
Sub testOutlook()
Dim olApp As Object ' Outlook.Application
Set olApp = CreateObject("Outlook.Application")
MsgBox (olApp2 Is Nothing)
End Sub
This will print "False" because we created the instance.
Let's say Outlook IS running. We can use this code to verify that using GetObject and CreateObject will refer to the existing instance:
Sub testOutlook()
Dim olApp As Object ' Outlook.Application
Dim olApp2 As Object ' Outlook.Application
Set olApp = GetObject(, "Outlook.Application")
MsgBox (olApp Is Nothing)
Set olApp2 = CreateObject("Outlook.Application")
MsgBox (olApp2 Is Nothing)
MsgBox "Same object? " & (olApp Is olApp2)
End Sub
This will print "False" (existing instance), "False" (our alleged "new instance"), but the last message box is "True" because the new instance is actually the same object as the existing instance.
So what do we do if we don't know if Outlook is running or not? As demonstrated above, CreateObject either created a new instance (if one didn't exist, as in the first example) or hooked the existing instance if Outlook was already open (as in the second example).
I see in your question that you commented out
'Dim w As Outlook.Application
presumably because this gives you the "User-defined type not defined" error.
This is likely because you have not set a reference to the Outlook library in your Excel-VBA project. This is done as follows: Tools > References > check "Microsoft Outlook xx.x Object Library". Then you can write this
Dim w As Outlook.Application
Set w = New Outlook.Application
' or,
'Set w = CreateObject("Outlook.Application")
which, by the way, results in compile-time (or "early") binding. And gives you the Outlook object intellisense.
Alternatively, you can omit setting the reference and declare w as a generic object and let it bind at run-time
Dim w As Object
Set w = CreateObject("Outlook.Application")
but runtime (or "late") binding is less efficient.
Do whatever feels best -- I'm going to go ahead and venture that chances are, you won't notice the difference in efficency. I'm a recent convert to the early-binding thing, really just because of the intellisense.
EDIT So you've created a new Outlook application, but you can't see it. If you look in the Windows task manager, you'll see that the process is there, running -- but it's just not showing on the screen. Unfortunately, some brilliant engineer at Microsoft decided that Outlook shouldn't have a Visible property like Word or Excel do, so we have to use an awkward workaround. Open one of the special folders e.g. the Inbox like this:
Dim w As Outlook.Application
Dim wInbox As Outlook.MAPIFolder
Set w = New Outlook.Application
Set wInbox = w.GetNamespace("MAPI").GetDefaultFolder(olFolderInbox)
wInbox.Display 'This makes Outlook visible
Set w = GetObject(, "Outlook.Application")
this should get running instance, if none is running catch error and do CreateObject
If you like, use this.
This is not a perfect solution, but you can open Outlook App when it's not be opened.
Function OpenOutlookApp(isSend As Boolean) As Boolean
' If it has opened, return true.
' my office version is 2016.
Dim oApp As Object
On Error GoTo ErrorHandle
On Error Resume Next
Set oApp = GetObject(, "Outlook.Application")
On Error GoTo 0
If oApp Is Nothing Then
Set oApp = CreateObject("Outlook.Application")
oApp.GetNamespace("MAPI").GetDefaultFolder(6).Display
End If
If isSend Then Call SendAndReceiveOutlookMail(False)
OpenOutlookApp = True
GoTo NonErrorHandle
ErrorHandle:
NonErrorHandle:
On Error GoTo 0
End Function
Sub SendAndReceiveOutlookMail(isQuit As Boolean)
Dim oApp As New Outlook.Application
On Error Resume Next
Call oApp.Session.LogOn("Outlook", "")
Call oApp.Session.SendAndReceive(True)
If isQuit Then oApp.Quit
Set oApp = Nothing
On Error GoTo 0
End Sub