Excel 2013 Outlook Recipient Resolve fails - vba

I have the following code that worked fine in Excel 2007 but fails in Excel 2013.
Dim lappOutlook As Outlook.Application
Dim lappNamespace As Outlook.Namespace
Dim lappRecipient As Outlook.RECIPIENT
Set lappOutlook = CreateObject("Outlook.Application")
Set lappNamespace = lappOutlook.GetNamespace("MAPI")
Set lappRecipient = lappNamespace.CreateRecipient("smithj1")
lappRecipient.Resolve
What I'm doing is parsing emails from a folder in my inbox. However, I need to resolve the recipient but that fails. The code you see starts out the sub and the remainder of the code follows the resolve method.
The error returned is:
Run-time error '287':
Application-defined or object-defined error
The error help really does not provide any useful information. Especially since this worked perfectly in Excel 2007 but now fails after an "upgrade" to Excel 2013.
I have tried "smithj1#company.org" and "John Smith" and "John A. Smith", etc. (those are not the real name) but nothing works. When I copied this to a laptop that still had Office 2007 on it, the code ran perfectly. Within the hour, the laptop was "upgraded" automatically to Office 2013 and the code failed.
Any help would be greatly appreciated.

Try waiting to see if there is a delayed response.
Private Sub openOutlook2()
Dim lappOutlook As Outlook.Application
Dim lappNamespace As Outlook.Namespace
Dim lappRecipient As Outlook.Recipient
Dim strAcc As String
Dim maxTries As Long
Dim errCount As Long
Set lappOutlook = CreateObject("Outlook.Application")
Set lappNamespace = lappOutlook.GetNamespace("MAPI")
strAcc = "smithj1"
Set lappRecipient = lappNamespace.CreateRecipient(strAcc)
maxTries = 2000
On Error GoTo errorResume
Retry:
DoEvents
' For testing error logic. No error with my Excel 2013 Outlook 2013 setup.
' Should normally be commented out
'Err.Raise 287
lappRecipient.Resolve
On Error GoTo 0
If lappRecipient.Resolved Then
Debug.Print strAcc & " resolved."
MsgBox strAcc & " resolved."
Else
Debug.Print strAcc & " not resolved."
MsgBox "No error: " & strAcc & " not resolved."
End If
ExitRoutine:
Set lappOutlook = Nothing
Set lappNamespace = Nothing
Set lappRecipient = Nothing
Debug.Print "Done."
Exit Sub
errorResume:
errCount = errCount + 1
' Try until Outlook responds
If errCount > maxTries Then
' Check if Outlook is there and Resolve is the issue
lappNamespace.GetDefaultFolder(olFolderInbox).Display
GoTo ExitRoutine
End If
Debug.Print errCount & " - " & Err.Number & ": " & Err.Description
Resume Retry
End Sub

Related

How to pass Outlook AppointmenItem data to Access form textbox

I have an Access form which will create an Outlook AppointmentItem for the current record.
The .Start and .Categories of the AppointmentItem are derived from user-input on the form.
I have a command button which will find and open the AppointmentItem so that the user may edit it.
After the user makes the edits I want to pass the edited information to the form controls so that the user can see the updated start time and category without having to open the AppointmentItem.
I am storing Public variables for the two bits of data. I cannot figure out the process by which the variables are updated with the data from the AppointmentItem.
Code for finding the existing AppointmentItem:
Option Compare Database
Public gdtStart As Date
Public gstrCat As String
Option Explicit
Function FindExistingAppt(strPath As String)
Dim OApp As Object
Dim OAppt As Object
Dim ONS As Object
Dim ORecipient As Outlook.Recipient
Dim OFolder As Object
Dim sFilter As String
Const olAppointmentItem = 1
Dim bAppOpened As Boolean
'Initiate our instance of the oApp object so we can interact with Outlook
On Error Resume Next
Set OApp = GetObject(, "Outlook.Application") 'Bind to existing instance of Outlook
If err.Number <> 0 Then 'Could not get instance of Outlook, so create a new one
err.Clear
Set OApp = CreateObject("Outlook.Application")
bAppOpened = False 'Outlook was not already running, we had to start it
Else
bAppOpened = True 'Outlook was already running
End If
On Error GoTo Error_Handler
Set OApp = GetObject(, "Outlook.Application")
Set ONS = OApp.GetNamespace("MAPI")
Set ORecipient = ONS.CreateRecipient("xxxxxxxxxxxxx")
'my example uses a shared folder but you can change it to your defaul
Set OFolder = ONS.GetSharedDefaultFolder(ORecipient, olFolderCalendar)
'use your ID here
sFilter = "[Mileage] = " & strPath & ""
If Not OFolder Is Nothing Then
Set OAppt = OFolder.Items.Find(sFilter)
If OAppt Is Nothing Then
MsgBox "Could not find appointment"
Else
With OAppt
.Display
End With
End If
End If
gdtStart = OAppt.Start
gstrCat = OAppt.Categories
Error_Handler_Exit:
On Error Resume Next
If Not OAppt Is Nothing Then Set OAppt = Nothing
If Not OApp Is Nothing Then Set OApp = Nothing
Exit Function
Error_Handler:
MsgBox "The following error has occurred" & vbCrLf & vbCrLf & _
"Error Number: " & err.Number & vbCrLf & _
"Error Source: FindExistingAppt" & vbCrLf & _
"Error Description: " & err.Description & _
Switch(Erl = 0, "", Erl <> 0, vbCrLf & "Line No: " & Erl), _
vbOKOnly + vbCritical, "An Error has Occurred!"
Resume Error_Handler_Exit
End Function
Here is the code from the command button which opens the AppointmentItem.
Private Sub cmdFindAppt_Click()
'Goes to the OutlookApp module and uses the FindExistingAppt function to look for an appointment that has
'already been created to the Warrants Outlook calendar, and if it found, opens the appointment. After edits are
'made the Appointment Date and Category are updated on the form.
Call FindExistingAppt(Me.ID)
Me.ApptDate = gdtStart
Me.Category = gstrCat
End Sub
How do I update the form controls with the Public variables?
After the code runs the form controls do not reflect the values of the stored Public variables.
If I open the AppointmentItem one more time (using the FindExistingAppt code - not by opening the AppointmentItem in Outlook proper), and close either by saving or not, then the form controls update.
This probably doesn't work because the VBA code continues to run after OAppt.Display.
So any changes you make and save to OAppt won't be read to your variables, because the function is already finished.
Try using the Modal parameter, this may halt the code until OAppt is closed.
With OAppt
.Display True
https://learn.microsoft.com/en-us/office/vba/api/outlook.appointmentitem.display
Also add Debug.Print commands and/or breakpoints before and after .Display to see what's happening.
The way you update those form controls should be working fine.
Try to check if the FindExistingAppt function really does assign values into public variables by debugging the function.
Use locals window to watch the variables values (gdtStart and gstrCat) while debugging.
Just sharing common practice:
If your procedure/routine does not return the value then you can declare it with Sub keyword instead Function keyword.

Run Time Error '440'; Array index out of bounds, when referencing attachment by index

I have an Outlook rule to run a script to save attachments.
I insert an Err.Clear right after Set olAttach = olItem.Attachments.item(1) to clear an error in the code but this eventually causes the rule to fail.
When I don't have the Err.Clear command the code stops and gives
Run Time Error '440'; Array index out of bounds.
Public Sub April26(item As Outlook.MailItem)
'
Dim olApp As Object
Dim olNS As Object
Dim myDate As Date
Dim olItems As Object
Dim olItem As Object
Dim olAttach As Object
On Error Resume Next
Set olApp = GetObject(, "Outlook.Application")
Err.Clear: On Error GoTo 0
If olApp Is Nothing Then
Set olApp = CreateObject("Outlook.Application")
Flg = True
End If
Set olNS = olApp.GetNamespace("MAPI")
Set olItems = olNS.GetDefaultFolder(olFolderInbox).Items
For Each olItem In olItems
If olItem.ReceivedTime > Date Then
If InStr(olItem.Body, "Michael Jordan") > 0 Then
Set olAttach = olItem.Attachments.item(1) '<---
'Err.Clear: On Error GoTo 0 '<---
If Not olAttach Is Nothing Then
On Error GoTo Finished
olAttach.SaveAsFile "C:\Users\Desktop\Outlook Downloads" & "\" & olAttach.FileName
Set olAttach = Nothing
Set olItem = Nothing
End If
End If
End If
Next
Set olApp = Nothing
Set olNS = Nothing
Set olItems = Nothing
Finished:
Exit Sub
End Sub
So I was able to answer my question. The conditions of my code were to save the attachments from emails with "Michael Jordan" in the body. These emails were only sent out on the early morning (between 12 AM and 6 AM). I know that I there are only FOUR emails sent and each email has ONE attachment so I put a break in my loop once I have a total count for four attachments.
Below is my modified code
Public Sub April26(item As Outlook.MailItem)
'
Dim olApp As Object
Dim olNS As Object
Dim myDate As Date
Dim olItems As Object
Dim olItem As Object
Dim olAttach As Object
Dim Date1 As String
Dim Date2 As String
Dim iAttachments As Integer
Date1 = Date & " " & TimeValue("6:00:00")
Date2 = Date & " " & TimeValue("00:00:00")
On Error Resume Next
Set olApp = GetObject(, "Outlook.Application")
Err.Clear: On Error GoTo 0
If olApp Is Nothing Then
Set olApp = CreateObject("Outlook.Application")
Flg = True
End If
Set olNS = olApp.GetNamespace("MAPI")
Set olItems = olNS.GetDefaultFolder(olFolderInbox).Items
For Each olItem In olItems
If olItem.ReceivedTime < Date1 Then
If olItem.ReceivedTime > Date2 Then
If InStr(olItem.Body, "Michael Jordan") > 0 Then
'MsgBox (olItem & " " & olItem.ReceivedTime)
iAttachments = olItem.Attachments.Count + iAttachments
Set olAttach = olItem.Attachments.item(1)
On Error GoTo Err_Handler
olAttach.SaveAsFile "C:\Desktop\Outlook Downloads" & "\" & olAttach.FileName
Set olAttach = Nothing
Set olItem = Nothing
If iAttachments = 4 Then Exit For
End If
End If
End If
Next
Set olAttach = Nothing
Set olItem = Nothing
Set olApp = Nothing
Set olNS = Nothing
Set olItems = Nothing
Exit Sub
Err_Handler:
MsgBox "An unexpected error has occurred." _
& vbCrLf & "Please note and report the following information to Darth Vader." _
& vbCrLf & "Macro Name: April26" _
& vbCrLf & "Error Number: " & Err.Number _
& vbCrLf & "Error Description: " & Err.Description _
, vbCritical, "Error!"
Exit Sub
End Sub
The error is due to there being no attachments.
With On Error Resume Next anticipated errors are bypassed. Since they are anticipated you will know how to handle them, or ignore if reasonable to do so.
Option Explicit
' Extra lines for running code from applications other than Outlook removed
Public Sub April26(olItem As MailItem)
Dim myDate As Date
Dim olAttach As Attachment
If olItem.ReceivedTime > Date Then
If InStr(olItem.Body, "Michael Jordan") > 0 Then
' Rare beneficial use of "On Error Resume Next"
On Error Resume Next
' Bypass error if there is no attachment
Set olAttach = olItem.Attachments.item(1)
'If there is an error olAttach remains whatever it was before
' In this case it is the initial value of Nothing
' Remove error bypass as soon as the purpose is served
On Error GoTo 0
If Not olAttach Is Nothing Then
olAttach.SaveAsFile "C:\Users\Desktop\Outlook Downloads" & "\" & olAttach.fileName
' If this type of error handling is in a loop,
' reinitialize
' Set olAttach = Nothing
End If
End If
End If
End Sub

Opening Outlook through VBA crashes for unknown reason

I am using this code to open a list of email-adresses directly in outlook. The email list consists of roughly 100 email-adresses.
If I let the code run for only parts of the list it works just fine for all different parts, but as soon as I let it run for the whole list I get a runtime error '5. Does anyone have a suggestion what causes this problem? I would be very thankful.
If ActiveWorkbook.Worksheets("Output").Range("I10").Value = "Wahr" Then
Dim strAddress As String
Dim lastCell As Long
Dim i As Integer
Worksheets("Output").Activate
lastCell = Range("B" & Rows.Count).End(xlUp).Row
For i = 13 To lastCell
If strAddress = "" Then
strAddress = Cells(i, 2).Value
Else
strAddress = strAddress & ";" & Cells(i, 2).Value
End If
Next i
ActiveWorkbook.FollowHyperlink Address:="mailto:" & strAddress 'this line gives me the error
End If
EDIT: The weird thing is, that it doesnt really matter which "groups" I choose. It seems to be a question of how many adresses I pick.
Not sure what you mean by I am using this code to open a list of email-adresses directly in outlook.
The code appears to create a single blank email with each cell in B13 downwards providing the email addresses?
Maybe this code below will help.
It uses late binding (so no references needed) to get a reference to Outlook, it then creates an email and adds the email addresses to it as recipients before finally displaying it. You can change the .Display to .Send to send the email rather than just display it.
Public Sub Test()
Dim oOL As Object
Dim oMail As Object
Dim rLastCell As Range
Dim rAddRange As Range
Dim rCell As Range
Set oOL = CreateOL
With ThisWorkbook.Worksheets("Output")
Set rLastCell = .Cells(.Rows.Count, 2).End(xlUp)
Set rAddRange = .Range("B13", rLastCell)
End With
Set oMail = oOL.CreateItem(0)
With oMail
For Each rCell In rAddRange
.Recipients.Add rCell.Value
Next rCell
.Display
End With
End Sub
Public Function CreateOL() As Object
Dim oTmpOL As Object
On Error GoTo ERROR_HANDLER
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'Creating an instance of Outlook is different from Excel. '
'There can only be a single instance of Outlook running, '
'so CreateObject will GetObject if it already exists. '
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Set oTmpOL = CreateObject("Outlook.Application")
Set CreateOL = oTmpOL
On Error GoTo 0
Exit Function
ERROR_HANDLER:
Select Case Err.Number
Case Else
MsgBox "Error " & Err.Number & vbCr & _
" (" & Err.Description & ") in procedure CreateOL."
Err.Clear
End Select
End Function

How to remove missing references?

I am using Outlook 2016 and Word 2016.
I have users with Outlook and Word 2013 which requires them to have a reference to the Outlook Library.
I have code that should check for and remove broken references and then add the references that I specified.
It does not remove the missing references so I remove the missing libraries manually and then run the code to add them.
This is the code, found on a MS Community Forum, which works under other circumstances:
Sub AddReference()
Dim strGUID(1 To 7) As String, theRef As Variant, i As Long
strGUID(1) = "{00062FFF-0000-0000-C000-000000000046}" ' Reference for Outlook library (see below reference printer to get more codes)
strGUID(2) = "{00020905-0000-0000-C000-000000000046}" ' Reference for Word library (see below reference printer to get more codes)
strGUID(3) = "{000204EF-0000-0000-C000-000000000046}" ' Reference for VBA library (see below reference printer to get more codes)
strGUID(4) = "{00020813-0000-0000-C000-000000000046}" ' Reference for Excel library (see below reference printer to get more codes)
strGUID(5) = "{2DF8D04C-5BFA-101B-BDE5-00AA0044DE52}" ' Reference for Office library (see below reference printer to get more codes)
strGUID(6) = "{0D452EE1-E08F-101A-852E-02608C4D0BB4}" ' Reference for MS Forms (see below reference printer to get more codes)
strGUID(7) = "{420B2830-E718-11CF-893D-00A0C9054228}" ' Reference for scripting (see below reference printer to get more codes)
On Error Resume Next
'Remove any missing references
For i = ThisWorkbook.VBProject.References.Count To 1 Step -1
Set theRef = ThisWorkbook.VBProject.References.Item(i)
If theRef.isbroken = True Then
ThisWorkbook.VBProject.References.Remove theRef
End If
Next i
For i = 1 To 7
'Clear any errors so that error trapping for GUID additions can be evaluated
Err.Clear
'Add the reference
ThisWorkbook.VBProject.References.AddFromGuid _
GUID:=strGUID(i), Major:=1, Minor:=0
'If an error was encountered, inform the user
Select Case Err.Number
Case Is = 32813
'Reference already in use. No action necessary
Case Is = vbNullString
'Reference added without issue
Case Else
'An unknown error was encountered, so alert the user
MsgBox "A problem was encountered trying to" & vbNewLine _
& "add or remove a reference in this file" & vbNewLine & "Please check the " _
& "references in your VBA project!", vbCritical + vbOKOnly, "Error!"
End Select
Next i
On Error GoTo 0
End Sub
This isn't the answer you're after as it doesn't deal with removing VBA references, etc.
It does show how to get MS Applications talking to each other without setting references though.
I've tested this on Word 2010, Outlook 2010 (had to change Application.PathSeparator to \), Excel 2003 and Excel 2010.
'Create an instance of Word & Outlook.
'Create a Word document and save it.
'Create an email and attach Word document to it.
Public Sub Test()
Dim oL As Object
Dim oW As Object
Dim nS As Object
Dim oMsg As Object
Dim oDoc As Object
Dim sDesktop As String
'Find the desktop.
sDesktop = CreateObject("WScript.Shell").specialfolders("Desktop")
'Create and save a Word document to the desktop.
Set oW = CreateWD
Set oDoc = oW.Documents.Add(DocumentType:=0) 'wdNewBlankDocument
oDoc.SaveAs sDesktop & Application.PathSeparator & "TempDoc"
'Create and save an email message, attach the Word doc to it.
Set oL = CreateOL
Set nS = oL.GetNamespace("MAPI")
Set oMsg = oL.CreateItem(0)
With oMsg
.To = "someaddress#somedomain"
.Body = "My Message"
.Subject = "My Subject"
.Attachments.Add sDesktop & Application.PathSeparator & "TempDoc.docx"
.Display 'or .Send
.Save
End With
End Sub
' Purpose : Creates an instance of Outlook and passes the reference back.
Public Function CreateOL() As Object
Dim oTmpOL As Object
On Error GoTo ERROR_HANDLER
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'Creating an instance of Outlook is different from Word. '
'There can only be a single instance of Outlook running, '
'so CreateObject will GetObject if it already exists. '
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Set oTmpOL = CreateObject("Outlook.Application")
Set CreateOL = oTmpOL
On Error GoTo 0
Exit Function
ERROR_HANDLER:
Select Case Err.Number
Case Else
MsgBox "Error " & Err.Number & vbCr & _
" (" & Err.Description & ") in procedure CreateOL."
Err.Clear
End Select
End Function
' Purpose : Creates an instance of Word and passes the reference back.
Public Function CreateWD(Optional bVisible As Boolean = True) As Object
Dim oTmpWD As Object
'''''''''''''''''''''''''''''''''''''''''''''''''''''
'Defer error trapping in case Word is not running. '
'''''''''''''''''''''''''''''''''''''''''''''''''''''
On Error Resume Next
Set oTmpWD = GetObject(, "Word.Application")
'''''''''''''''''''''''''''''''''''''''''''''''''''''''
'If an error occurs then create an instance of Word. '
'Reinstate error handling. '
'''''''''''''''''''''''''''''''''''''''''''''''''''''''
If Err.Number <> 0 Then
Err.Clear
On Error GoTo ERROR_HANDLER
Set oTmpWD = CreateObject("Word.Application")
End If
oTmpWD.Visible = bVisible
Set CreateWD = oTmpWD
On Error GoTo 0
Exit Function
ERROR_HANDLER:
Select Case Err.Number
Case Else
MsgBox "Error " & Err.Number & vbCr & _
" (" & Err.Description & ") in procedure CreateWD."
Err.Clear
End Select
End Function

Inserting email signature using vba in Excel 2013

This sub in an Excel VBA application that has worked well for years, inserting an Outlook signature into an email before displaying the email for me to send (.Display). This has worked in Excel 2007 in Windows XP and 2013 in Windows 7.
Now I have Windows 8.1 and Office 2013 this comes out with Error 91 in my error routine. Could it be a problem with one of the References? - or some change needed in the code?
Sub InsertSig2007(strSigName As String)
Dim objItem As Object
Dim objInsp As Outlook.Inspector
' requires a project reference to the
' Microsoft Office library
Dim objCBP As Office.CommandBarPopup
Dim objCBP2 As Office.CommandBarPopup
Dim objCBB As Office.CommandBarButton
Dim colCBControls As Office.CommandBarControls
Set objInsp = ActiveInspector
If Not objInsp Is Nothing Then
Set objItem = objInsp.CurrentItem
If objItem.Class = olMail Then
' get Insert menu
Set objCBP = objInsp.CommandBars.ActiveMenuBar.FindControl(, 30005)
' get Signature submenu
Set objCBP2 = objCBP.CommandBar.FindControl(, 5608)
If Not objCBP2 Is Nothing Then
Set colCBControls = objCBP2.Controls
For Each objCBB In colCBControls
Debug.Print objCBB.Caption
If objCBB.Caption = strSigName Then
objCBB.Execute ' **** see remarks
Exit For
End If
Next
End If
End If
End If
Set objInsp = Nothing
Set objItem = Nothing
Set colCBControls = Nothing
Set objCBB = Nothing
Set objCBP = Nothing
Set objCBP2 = Nothing
End Sub
"this comes out with Error 91 in my error routine" When debugging do not use an error routine. That way you see the line with the problem and can say what it is in your question.
It is probably
Set objCBP = objInsp.CommandBars.ActiveMenuBar.FindControl(, 30005)
See CommandBars.FindControl Method (Office)
"The use of CommandBars in some Microsoft Office applications has been superseded by the new ribbon component of the Microsoft Office Fluent user interface."
Note: CommandBars.ExecuteMso Method (Office) works in 2013 but I believe the signature button is not available.
You will surely find a replacement for your code here Insert Outlook Signature in mail.
Likely this one:
Sub Mail_Outlook_With_Signature_Html_2()
' Don't forget to copy the function GetBoiler in the module.
' Working in Office 2000-2013
'Dim OutApp As Object
Dim OutMail As Object
Dim strbody As String
Dim SigString As String
Dim Signature As String
'Set OutApp = CreateObject("Outlook.Application")
'Set OutMail = OutApp.CreateItem(0)
Set OutMail = CreateItem(0)
strbody = "<H3><B>Dear Customer Ron de Bruin</B></H3>" & _
"Please visit this website to download the new version.<br>" & _
"Let me know if you have problems.<br>" & _
"Ron's Excel Page" & _
"<br><br><B>Thank you</B>"
'Change only Mysig.htm to the name of your signature
SigString = Environ("appdata") & _
"\Microsoft\Signatures\Mysig.htm"
If Dir(SigString) <> "" Then
Signature = GetBoiler(SigString)
Else
Signature = ""
End If
On Error Resume Next
With OutMail
'.To = "ron#debruin.nl"
.CC = ""
.BCC = ""
.Subject = "This is the Subject line"
.HTMLBody = strbody & "<br>" & Signature
'.Send
'or use
.Display
End With
On Error GoTo 0
Set OutMail = Nothing
'Set OutApp = Nothing
End Sub
Function GetBoiler(ByVal sFile As String) As String
'Dick Kusleika
Dim fso As Object
Dim ts As Object
Set fso = CreateObject("Scripting.FileSystemObject")
Set ts = fso.GetFile(sFile).OpenAsTextStream(1, -2)
GetBoiler = ts.readall
ts.Close
End Function