Getting "object variable or with block variable not set" within Outlook VBA sometimes - vba

I have a fairly straightforward VBA script that accepts meeting requests in Outlook (2013). It works fine most of the times, but for some meeting requests it gives me "object variable or with block variable not set" on this line
Set oResponse = oAppt.Respond(olMeetingAccepted, True)
I've tried to look at the different meeting requests to figure out any differences which might be triggering it but for all purposes they look like identical requests (of course they're from different senders with different subject and time, but nothing that I can see as triggering a fail).
Any thoughts what might be going on? Here's the complete Sub (it gets triggered by an outlook rule)
Sub AutoAcceptMeetings(oRequest As MeetingItem)
Dim senderName As String
Dim subjectName As String
Dim meetingTime As String
Dim senderContains As Integer
Dim subjectContains As Integer
Dim oResponse As MeetingItem
Dim oAppt As AppointmentItem
On Error GoTo debugs
If oRequest.MessageClass <> "IPM.Schedule.Meeting.Request" Then
Exit Sub
End If
Set oAppt = oRequest.GetAssociatedAppointment(True)
senderName = oRequest.senderName
subjectName = oRequest.Subject
senderContains = InStr(1, senderName, "Gina")
'Her meeting invitations don't have a reminder set.
If (senderContains > 0) Then
oAppt.ReminderSet = True
oAppt.ReminderMinutesBeforeStart = 15
End If
senderContains = InStr(1, senderName, "Jim")
If (senderContains > 0) Then 'I don't want a reminder
oAppt.ReminderSet = False
oAppt.BusyStatus = olTentative
oAppt.Save
Else 'useful meetings. accept and send response.
meetingTime = oAppt.Start
Set oResponse = oAppt.Respond(olMeetingAccepted, True)
oResponse.Send
MsgBox ("Meeting accepted " + subjectName + " from " + senderName + " for " + meetingTime)
End If
debugs:
If Err.Description <> "" Then MsgBox (Err.Description + " - Source: AutoAcceptMeetings")
End Sub

So, the issue was that I was trying to send a "response" to a meeting request that didn't require any responses. On the front end (outlook) if you accept the meeting, it goes into your calendar and the request gets deleted but no response goes to the organizer (people do that when they invite a large group and don't necessarily care to know who's attending).
Anyway, the solution for me was to put in a simple check before actually responding to the request.
If (oAppt.ResponseRequested) Then
Set oResponse = oAppt.Respond(olMeetingAccepted, True)
oResponse.Send
End If

Related

How to reply to mail based on attachment extension?

I can read code, and adjust code a bit.
I've got access to a company email (say invoice#rr.com).
I want code which looks through all new mail in the inbox of invoice#rr.com (best if this works even when Outlook is not open, but a manually clicked macro would make me happy) and reply to all (with attachment) when:
there is more then one attachment (exception is one .xml and one .pdf file)
the attachment is not .pdf, .xml or .icf
when there is no attachment at all
when the title has the word "reminder"
when the message has the word "reminder"
Besides that, the code needs to move the mail to a subfolder called "send back".
I've been reading forums and one of the problems is a picture in a signature also counts as an attachment.
First try after help from Tony:
Sub reply()
'still need to get rid of all the stuff i dont use below (up to the *) but still not sure about the code so I left it here for now
Dim olInspector As Outlook.Inspector
Dim olDocument As Outlook.DocumentItem
Dim olSelection As Outlook.Selection
Dim olReply As MailItem
Dim olAtt As Attachment
Dim olFileType As String
Dim AttachCount As Long
Dim AttachDtl() As String
Dim ExcelWkBk As Excel.Workbook
Dim FileName As String
Dim FolderTgt As MAPIFolder
Dim HtmlBody As String
Dim InterestingItem As Boolean
Dim InxAttach As Long
Dim InxItemCrnt As Long
Dim PathName As String
Dim ReceivedTime As Date
Dim RowCrnt As Long
Dim SenderEmailAddress As String
Dim SenderName As String
Dim Subject As String
Dim TextBody As String
Dim myDestFolder As Outlook.Folder
'*
Set myDestFolder = Session.Folders("Outlook Data File").Folders("replied")
Set Myselect = Outlook.ActiveExplorer.Selection '(i use this in my test to only process selected test mails)
'Set FolderTgt = Session.Folders("invoice#rr.com").Folders("Inbox") ***(this will replace the code above)
For InxItemCrnt = Myselect.Items.Count To 1 Step -1 '(myselect = foldertgt in live)
With Myselect.Items.Item(InxItemCrnt) '(myselect = foldertgt in live)
'still need a workaround for mail with (1 .PDF and 1 .ICF) or (1 .PDF and 1 .XML)
'those combinations are the only combinations when more then one attachment is allowed
'1st filter
If AttachCount = 0 Then 'no attachment = reply
Reply0
.move myDestFolder
Else
'2nd filter
If AttachCount > 1 Then 'more then one attachment = reply
Reply1
.move myDestFolder
Else
'3rd filter
If InStr(Subject, "Reminder") = 0 Then 'reminders need to go to a different mailbox
Reply2
.move myDestFolder
Else
'4th filter
Select Case olFileType
Case ".pdf, .icf, .xml"
If olFileType = LCase$(Right$(olAtt.FileName, 4)) Then
Exit Sub 'if attachment = pdf or ICF then this sub can exit
Else
Reply3 'all mails with incorrect files
.move myDestFolder
End Select
End If
End If
End If
End If
End With
'replies below
Reply0:
Set olReply = Item.Reply '// Reply if no attachment found
olReply.Body = "this is an automatic generated mail." & vbCrLf & vbCrLf & vbCrLf & vbCrLf & vbCrLf & ".... insert text...." 'still need to insert some text
olReply.Send
Reply1:
Set olReply = Item.Reply '// Reply more then one attachment
olReply.Body = "this is an automatic generated mail." & vbCrLf & vbCrLf & vbCrLf & vbCrLf & vbCrLf & ".... insert text...." 'still need to insert some text
olReply.Send
Reply2:
Set olReply = Item.Reply '// Reply reminders need to go to reminder#rr.com
olReply.Body = "this is an automatic generated mail." & vbCrLf & vbCrLf & vbCrLf & vbCrLf & vbCrLf & ".... insert text...." 'still need to insert some text
olReply.Send
Reply3:
Set olReply = Item.Reply '// Reply not correct file
olReply.Body = "this is an automatic generated mail." & vbCrLf & vbCrLf & vbCrLf & vbCrLf & vbCrLf & ".... insert text...." 'still need to insert some text
olReply.Send
Next
Set olInspector = Nothing
Set olDocument = Nothing
Set olSelection = Nothing
Set olAtt = Nothing
End Sub
2nd try after some more help from Tony: (note: I'm Dutch so some code has dutch words I'll explain them in English behind the code, it basicly is copy paste from his answer, all credits to Tony)
Sub reply()
Dim Fso As New FileSystemObject
Dim DiagFile As TextStream
Dim FldrInvInbox As MAPIFolder
Dim InxA As Long
Dim InxItemCrnt As Long
Dim NumIcfAttach As Long
Dim NumPdfAttach As Long
Dim NumXmlAttach As Long
Dim NumDocAttach As Long
Dim NumDoxAttach As Long
Dim PathDiag As String
Dim Pos As Long
Dim ProcessThisEmail As Boolean
Dim Subject As String
Dim ReminderInBody As Boolean
Dim ReminderInSubject As Boolean
Dim ReminderInBody1 As Boolean
Dim ReminderInSubject1 As Boolean
Set FldrInvInbox = Session.Folders("invoice#rr.com").Folders("Postvak IN") 'Postvak IN = Inbox)
PathDiag = "z:\VBA test" 'location for diagnostics report
Set DiagFile = Fso.CreateTextFile(PathDiag & "\Diag.txt", True, False)
For InxItemCrnt = FldrInvInbox.Items.Count To 1 Step -1
With FldrInvInbox.Items.Item(InxItemCrnt)
' It is unlikely an Inbox will contain anything but emails
' but it does no harm to check
If .Class = olMail Then
' Extract information that will identify if this email is to be processed
ProcessThisEmail = True ' Assume True until find otherwise
'Below i'm looking for reminder, payment reminder and other similiar text in subject, dutch words are betalingsherinnering and openstaande posten
If InStr(1, LCase(.Subject), "betalingsherinnering") = 0 Then
ReminderInSubject = False
Else
ReminderInSubject = True
ProcessThisEmail = False
End If
If InStr(1, LCase(.Subject), "openstaande posten") = 0 Then
ReminderInSubject1 = False
Else
ReminderInSubject1 = True
ProcessThisEmail = False
End If
'Below i'm looking for reminder, payment reminder and other similiar text in mail, dutch words are betalingsherinnering and openstaande posten
If InStr(1, LCase(.Body), "betalingsherinnering") = 0 Then
ReminderInBody = False
Else
ReminderInBody = True
ProcessThisEmail = False
End If
If InStr(1, LCase(.Body), "openstaande posten") = 0 Then
ReminderInBody1 = False
Else
ReminderInBody1 = True
ProcessThisEmail = False
End If
NumIcfAttach = 0
NumPdfAttach = 0
NumXmlAttach = 0
NumDocAttach = 0
For InxA = 1 To .Attachments.Count
Select Case LCase(Right$(.Attachments(InxA).FileName, "3"))
Case "txt"
NumIcfAttach = NumIcfAttach + 1 'code will be changed soon, need to look at ICF in the name of the attachment
Case "pdf"
NumPdfAttach = NumPdfAttach + 1
Case "doc"
NumDocAttach = NumDocAttach + 1
Case "xml"
NumXmlAttach = NumXmlAttach + 1
End Select
Next InxA
Else ' Not email
ProcessThisEmail = False
End If
End With
' Decide if email is to be processed
If ProcessThisEmail = True Then
If NumXmlAttach > 1 Then
ProcessThisEmail = False
Else
If NumDocAttach <> 0 Then
ProcessThisEmail = False
Else
If NumPdfAttach > 1 Then
ProcessThisEmail = False
Else
If NumIcfAttach > 1 Then
ProcessThisEmail = False
Else
If NumIcfAttach + NumPdfAttach = 2 Then
ProcessThisEmail = True
Else
If NumXmlAttach + NumPdfAttach = 2 Then
ProcessThisEmail = True
Else
If NumXmlAttach = 1 And NumIcfAttach = 0 And NumPdfAttach = 0 And NumDocAttach = 0 Then
ProcessThisEmail = True
Else
If NumPdfAttach = 1 And NumIcfAttach = 0 And NumXmlAttach = 0 And NumDocAttach = 0 Then
ProcessThisEmail = True
Else
If NumIcfAttach = 1 And NumXmlAttach = 0 And NumPdfAttach = 0 And NumDocAttach = 0 Then
ProcessThisEmail = True
Else
If NumXmlAttach + NumPdfAttach + NumIcfAttach = 0 Then
ProcessThisEmail = False
Else
If NumXmlAttach + NumIcfAttach = 2 Then
ProcessThisEmail = False
Else
If NumXmlAttach + NumPdfAttach + NumIcfAttach = 3 Then
ProcessThisEmail = False
Else
If NumIcfAttach + NumPdfAttach <> 2 Then
ProcessThisEmail = False
Else
If NumXmlAttach + NumPdfAttach <> 2 Then
ProcessThisEmail = False
Else
Procisthisemail = False
End If
End If
End If
End If
End If
End If
End If
End If
End If
End If
End If
End If
End If
End If
End If
' Output diagnostic information
DiagFile.WriteLine "----- " & InxItemCrnt & " -----"
With FldrInvInbox.Items.Item(InxItemCrnt)
DiagFile.WriteLine "ReceivedTime=" & .ReceivedTime
DiagFile.WriteLine "Sender=" & .Sender
Subject = .Subject
For Pos = Len(Subject) To 1 Step -1
If AscW(Mid(Subject, Pos, 1)) < 1 Or _
AscW(Mid(Subject, Pos, 1)) > 255 Then
Subject = Replace(Subject, Mid(Subject, Pos, 1), "?")
End If
Next
DiagFile.WriteLine "Subject=" & Subject
DiagFile.WriteLine "Reminders: Subject 1=" & ReminderInSubject & _
" Subject 2=" & ReminderInSubject1 & _
" Body 1=" & ReminderInBody & _
" Body 2=" & ReminderInBody1
DiagFile.WriteLine "Attachment counts: ICF=" & NumIcfAttach & _
" PDF=" & NumPdfAttach & " XML=" & NumXmlAttach & _
" Doc=" & NumDocAttach
DiagFile.WriteLine "ProcessThisEmail=" & ProcessThisEmail
End With
' Process email if required
If ProcessThisEmail Then
End If
Next InxItemCrnt
DiagFile.Close
End Sub
My first reaction is: there is way too much untested code in your revised question. I plan to review your code but most of this answer is a tutorial explaining how I would have tackled your requirement.
None of us were born with the knowledge to write the macro you need. I started with Excel VBA which I believe was lucky since the training material for Excel VBA is much better than that for Outlook VBA. I visited a good library and borrowed several “Teach yourself to program Excel” books. I tried them all and then bought the one that was best for my learning style. I would recommend you invest a few days learning Excel VBA. I am confident that this investment will quickly repay itself. I did buy a highly recommended Outlook VBA but was not impressed. The transition from Excel to Outlook was not as easy as it could have been because I have never found a good explanation of the Outlook Object Model. Most of my knowledge is the result of much experimentation over many years. This background means I can usually look at some badly explained Outlook property and be able to deduce what they meant to say.
One of my advantages is that I have spent time studying development and testing theory. There is little in your code that is wrong but I believe a different approach would produce the desired result more quickly.
Another advantage which I would recommend to you is a folder on my system named “Resources” with sub-folders by topic. Every time I complete a development, I look through the code for ideas I might need again. I capture each idea in a file in the appropriate sub-folder with sample code, references to the source and notes on anything I found difficult. I don’t use VBA often enough to remember everything I have learnt. Being able to look for relevant files when starting a new development saves me a lot of time.
That’s enough general points. From your original question, I think you need the following for your requirement:
To read up or down the Inbox of invoice#rr.com.
To identify the number of attachments of an email and, if any, their extensions.
To check if the title of an email includes "remainder".
To check if body of an email includes "remainder".
To reply to selected emails
To move selected emails to folder “send back”
Your original specification of which emails were to be selected is not clear to me. Your added code is a little clearer but adds the complication that you appear to envisage different replies for different emails.
In your code, you do not read up or down the Inbox of invoice#rr.com. Instead you use Inspector to process selected emails. This would allow you to select an email with no attachments, say, and test how you code handles it. I do not think this is a good idea. For me, reading down the inbox and selecting the emails to be processed is the larger and more complicated block of code. I would want to write and test that code before writing the code to replying or moving emails. I would not want to reply to emails until I knew I had everything else correct. I would not want to move emails to a different folder until near the end of testing because I would not want to move them back for a retest.
The potential problem with my approach is the number of emails in the Inbox of invoice#rr.com. How do I test each email is correctly identified as needing a reply or not needing a reply? VBA comes with some diagnostic aids but one of my favourite technique is to write the envelope for my code but to output diagnostic text identifying the decisions made by the code without acting on those decisions. The code I have written shows what I mean by this.
To output diagnostic text, I can use something like Debug.Print "xxxx=" & xxxx where xxxx is a variable. This outputs to the Immediate Window which is often the most convenient technique. But you can only see the last 200 or so displays with Debug.Print and I suspect this will not be enough. Instead I will output to a text file. I do not do this often enough to remember the syntax so I have a file to remind me. File “Output to diagnostic file.txt” contains:
' Needs reference to Microsoft Scripting Runtime
Dim Fso As New FileSystemObject
Dim DiagFile As TextStream
Dim PathDiag As String
PathDiag = ThisWorkbook.Path
PathDiag = CreateObject("WScript.Shell").specialfolders("Desktop")
Set DiagFile = Fso.CreateTextFile(PathDiag & "\Diag.txt", True, False)
DiagFile.WriteLine ""
DiagFile.Close
I do not need the reminder about “Microsoft Scripting Runtime” for Outlook because I referenced it when I first installed Outlook. You will need to open the Outlook VBA Editor, click Tools and select References from the drop down menu. Scroll down the list of libraries and tick “Microsoft Scripting Runtime”. Without this reference, the compiler will not recognise “FileSystemObject” or “TextStream”. I use the first value for PathDiag if I am working with Excel. Here I will use the second value which will create the file on the desktop.
I have taken code from the answer I referenced in my comment. I renamed some of the variables and simplified the handling of attachments. I inserted code from file “Output to diagnostic file.txt”. I added code to extract the values needed for selecting emails. This code only involves simple (for me) statements that I remember how to use correctly. I added the code to output diagnostics to the text file. Here I hit a problem. Execution stopped on DiagFile.WriteLine “Subject=" & .Subject saying this an invalid call. It took me a while to identify the cause and add code to fix it. I will explain this latter. Here is my code:
Option Explicit
Sub ReplyToInvoiceEmails()
Dim Fso As New FileSystemObject
Dim DiagFile As TextStream
Dim FldrInvInbox As MAPIFolder
Dim InxA As Long
Dim InxItemCrnt As Long
Dim NumIcoAttach As Long
Dim NumPdfAttach As Long
Dim NumXmlAttach As Long
Dim PathDiag As String
Dim Pos As Long
Dim ProcessThisEmail As Boolean
Dim Subject As String
Dim ReminderInBody As Boolean
Dim ReminderInSubject As Boolean
Set FldrInvInbox = Session.Folders("tonydallimore23#gmail.com").Folders("Inbox")
PathDiag = CreateObject("WScript.Shell").specialfolders("Desktop")
Set DiagFile = Fso.CreateTextFile(PathDiag & "\Diag.txt", True, False)
For InxItemCrnt = FldrInvInbox.Items.Count To 1 Step -1
With FldrInvInbox.Items.Item(InxItemCrnt)
' It is unlikely an Inbox will contain anything but emails
' but it does no harm to check
If .Class = olMail Then
' Extract information that will identify if this email is to be processed
ProcessThisEmail = True ' Assume True until find otherwise
If InStr(1, LCase(.Subject), "reminder") = 0 Then
ReminderInSubject = False
Else
ReminderInSubject = True
End If
If InStr(1, LCase(.Body), "reminder") = 0 Then
ReminderInBody = False
Else
ReminderInBody = True
End If
NumIcoAttach = 0
NumPdfAttach = 0
NumXmlAttach = 0
For InxA = 1 To .Attachments.Count
Select Case LCase(Right$(.Attachments(InxA).Filename, "3"))
Case "ico"
NumIcoAttach = NumIcoAttach + 1
Case "pdf"
NumPdfAttach = NumPdfAttach + 1
Case "xml"
NumXmlAttach = NumXmlAttach + 1
End Select
Next InxA
Else ' Not email
ProcessThisEmail = False
End If
End With
' Decide if email is to be processed
If ProcessThisEmail Then
If ReminderInSubject Or ReminderInBody Then
ProcessThisEmail = False
ElseIf NumXmlAttach = 1 Then
ProcessThisEmail = False
End If
End If
' Output diagnostic information
DiagFile.WriteLine "----- " & InxItemCrnt & " -----"
With FldrInvInbox.Items.Item(InxItemCrnt)
DiagFile.WriteLine "ReceivedTime=" & .ReceivedTime
DiagFile.WriteLine "Sender=" & .Sender
Subject = .Subject
For Pos = Len(Subject) To 1 Step -1
If AscW(Mid(Subject, Pos, 1)) < 1 Or _
AscW(Mid(Subject, Pos, 1)) > 255 Then
Subject = Replace(Subject, Mid(Subject, Pos, 1), "?")
End If
Next
DiagFile.WriteLine "Subject=" & Subject
DiagFile.WriteLine "Reminders: Subject=" & ReminderInSubject & _
" Body=" & ReminderInBody
DiagFile.WriteLine "Attachment counts: ICO=" & NumIcoAttach & _
" PDF=" & NumPdfAttach & " XML=" & NumXmlAttach
DiagFile.WriteLine "ProcessThisEmail=" & ProcessThisEmail
End With
' Process email if required
If ProcessThisEmail Then
End If
Next InxItemCrnt
DiagFile.Close
End Sub
The first executable statement is Set FldrInvInbox = Session.Folders("tonydallimore23#gmail.com").Folders("Inbox"). You must replace "tonydallimore23#gmail.com" with "invoice#rr.com" or the real name for this store. Apart from this change, this code should run without problems on your system.
Next are the statements to prepare the diagnostic text file and then: For InxItemCrnt = FldrInvInbox.Items.Count To 1 Step -1.
FldrInvInbox.Items is a collection holding all the items in FldrInvInbox. A collection is like an array (if you know what an array is) except you can add items to the middle of a collection and delete items from the middle. FldrInvInbox.Items.Count is the number of items in FldrInvInbox.Items. I am accessing items in this collection by their position. If the code decides item 5 is to be moved to another folder, item 6 become item 5, item 7 becomes item 6 and so on. This would mess up the For-Loop. I am accessing this collection starting from the end. If I move item 1000 to a different folder then items 1 to 999, which I have yet to process, do not move so the For-Loop works properly.
The next block of code extracts properties to variables. I think I have extracted every property you need but you must check. The next block of code decides if an email is to be processed. I like to divide code into blocks like this because it is easier to write and easier to understand if you need to change it in a year’s time. I do not understand how you want to select emails and I am sure my selection code is wrong. You will have to correct this block of code or provide more information on the selection process so I can correct it.
Next is code to create the diagnostic output. On my system, the diagnostic output looks like:
----- 55 -----
ReceivedTime=09/08/2018 13:03:09
Sender=TechTarget Channel Media
Subject=Channel ecosystem sees major shift in partner types
Reminders: Subject=False Body=False
Attachment counts: ICO=0 PDF=0 XML=0
ProcessThisEmail=True
----- 54 -----
ReceivedTime=09/08/2018 11:48:10
Sender=TechTarget
Subject=Industrial control systems a specialised cyber target
Reminders: Subject=False Body=False
Attachment counts: ICO=0 PDF=0 XML=0
ProcessThisEmail=True
----- 53 -----
The first three lines of each email identify the email so you can locate it in the folder. The second three lines are the selection values which I know are wrong.
If I had missed some selection values, you will have to add them. You will have to correct my selection code. You want every “ProcessThisEmail=True/False” line to be correct before we move on to the reply code.
The problem I encountered with the diagnostic code was because of emojis. Execution stopped on the statement outputting the subject for some emails and it took me sometime to locate the cause. The diagnostic file is a simple ASCII text file and an emoji cannot be output to an ASCII text file. I thought of ignoring the problem since you were unlikely to have emojis in your subject. I decided to fix the problem because you have neither the experience to diagnose the problem nor to experience fix it if you did diagnose it. Have a look at my code and try to understand what I have done.
I need you to complete tmy code before we move on to the next section. I will add some text about the next section later but this section is much later than I promised so I will post what I have now.
This next paragraphs are to get you thinking about the email bodies you will create and the ones you have checked for “Reminder”.
An Outlook email can have three bodies: a text body, an Html body and a Rich Text Format (RTF) body. I have never received an email with a RTF body. I have seen a question about them but to my mind they are obsolete; perhaps they were useful before Html became so well known. I will ignore the theoretical existence of RTF bodies. An Outlook email can have a text body, an Html body or both. If there is an Html body, that is the body that is shown to the user. I rarely receive emails without an Html body. The Html bodies I receive vary enormously in both appearance and the Html used to create that appearance. Many are very complicated with style sheets and nested table so the result will look good on a laptop or a smartphone or whatever device the user views it on. I said, an Outlook email can have an Html body without a text body but I cannot find one in my archives for the last few years. I suspect they are being created by Outlook from the Html body by deleting all the Html tags and adding carriage-return-linefeeds to mark deleted paragraphs and table cells.
With an Outlook email, property Body is the text body and property HtmlBody is the Html body. In my code I only check the text body for “Reminder”. This seems sensible since the text body will be a lot smaller and I cannot find an email without a text body. If you want to be ultra-cautious, I will show you how to check the Html body if there is no text body or you might like to consider how to do this as a training exercise.
In your code you have:
olReply.Body = "this is an automatic generated mail." & vbCrLf & vbCrLf & _
vbCrLf & vbCrLf & vbCrLf & ".... insert text...."
You might find that the following gives a more attractive appearance since email packages tend to use a more attractive font when displaying Html bodies if none is specified:
olReply.Body = ""
olReply.HtmlBody = "<HTML><BODY>" & _
"<P>this is an automatic generated mail.</P>" & _
"<P>.... insert text....</P>" & _
"</BODY>" & "</HTML>"
This is very basic Html and is now depreciated but it shows an Html body could be created for little more effort than creating a text body. Html also allows formatting (bold, italic, font size, font colour and so on) which might be helpful.

Treating Item As MailItem

I am creating an VBA application in Outlook 2016. It analyzes an incoming email and takes its subject line to search for duplicate (or close to duplicate) subject lines. I use a for-each loop to go through a list of Items (which are emails within the inbox) and analyze each one for the criteria.
Once a response is required, both the incoming email and the duplicate email are flagged so show that I have already responded to them.
I know both Item and olItem should both be Item objects. The problem I am having is in the line:
If InStr(1, GetPreceedingSubject(olItem.Subject), GetPreceedingSubject(SubjectString)) <> 0 _
And olItem.FlagRequest <> "Follow up" Then
It gives me the error
"Run-time error '438': Object doesn't support this property or method"
I know it is the olItem because it is the only part of the function that I had changed before I got the error. This strikes me as odd because the following snippet still works:
' flag both the emails that prompted the response
With Item
' due this week flag
.MarkAsTask olMarkThisWeek
' sets a specific due date
.TaskDueDate = Now + 3
.FlagRequest = "Follow up"
.FlagStatus = 2
.ReminderSet = False
.Save
End With
With olItem
' due this week flag
.MarkAsTask olMarkThisWeek
' sets a specific due date
.TaskDueDate = Now + 3
.FlagRequest = "Follow up"
.FlagStatus = 2
.ReminderSet = False
.Save
End With
So in the first code snippet, it appears that it is treating the olItem as an object, but in the next one it allows me to treat it like a MailItem object. Any suggestions? I have looked up ways to cast from Item to MailItem, even just temporarily for that line of code, but obviously to no avail. Full subroutine below:
Private Sub myOlItems_ItemAdd(ByVal Item As Object)
If ParsingEnabled = False Then
Exit Sub
End If
Dim SubjectString As String ' tracks the control word to search the subject line for
Dim pingCount As Integer ' tracks the number of copies found.
Dim TimeDiff As Double
Dim Protocol As Variant
Dim FlagStatus As Integer
pingCount = 0
SubjectString = Item.Subject ' searches subject line for this word
' If the email is a read receipt, then move it to a different folder
If TypeName(Item) = "ReportItem" Then
NullPrompt = MoveFolders(Item, "Read")
If NullPrompt >= 0 Then
setLblDebug ("Read receipt: " & Mid(SubjectString, 7, Len(SubjectString)))
Item.UnRead = False
Else
NullPrompt = setLblDebug("Error when moving read receipt. Please check inbox and correct", lngRed)
End If
End If
' Check to make sure it is an Outlook mail message, otherwise
' subsequent code will probably fail depending on what type
' of item it is.
If TypeName(Item) = "MailItem" Then
' display the message
setLblDebug ("Incoming Message: " & Item.Subject)
Item.UnRead = False ' mark message as read
' Iterate through each item of the list
For Each olItem In myOlItems
If InStr(1, GetPreceedingSubject(olItem.Subject), GetPreceedingSubject(SubjectString)) <> 0 _
And olItem.FlagRequest <> "Follow up" Then
Protocol = ProtocolCode(Item.Subject)
If Protocol(0) <> 0 Then
' Time difference between the 2 emails
TimeDiff = (Item.ReceivedTime - olItem.ReceivedTime) * 24 ' Gives the hour difference
' If time difference is 0, then it is the same email
If Protocol(0) >= TimeDiff And TimeDiff <> 0 Then
' flag both the emails that prompted the response
With Item
' due this week flag
.MarkAsTask olMarkThisWeek
' sets a specific due date
.TaskDueDate = Now + 3
.FlagRequest = "Follow up"
.FlagStatus = 2
.ReminderSet = False
.Save
End With
With olItem
' due this week flag
.MarkAsTask olMarkThisWeek
' sets a specific due date
.TaskDueDate = Now + 3
.FlagRequest = "Follow up"
.FlagStatus = 2
.ReminderSet = False
.Save
End With
' email and call if required
RenderMail (olItem)
If Protocol(1) = 1 Then
NullPrompt = RenderCallPrompt(olItem.Subject, Item.ReceivedTime)
End If
' set the debug prompt message
NullPrompt = setLblDebug("Response Made: " & Item.Subject & " [" & Item.ReceivedTime & "]", lngBlue)
If True Then Exit For ' Reponse made, stop looking for additional emails
End If
End If
End If
Next olItem
End If
End Sub
You cannot treat an Object which is not a MailItem as a MailItem.
MailItem is a subset of Object. Object encompasses TaskItem, AppointmentItem and others.
Other types will not necessarily have the properties of a MailItem.
In your code:
' Check to make sure it is an Outlook mail message, otherwise
' subsequent code will probably fail depending on what type
' of item it is.
If TypeName(Item) = "MailItem" Then
Add the same test to ensure olItem is a MailItem.
For Each olItem In myOlItems
' Check to make sure it is an Outlook mail message, otherwise
' subsequent code will probably fail depending on what type
' of item it is.
If TypeName(olItem) = "MailItem" Then
'
End If
Next olItem

Reply body conditioned by mailbox it is sent from

So I have multiple mailboxes under my Outlook account and I am trying to get them to generate reply template based on the mailbox I am replying from (one is private, one is shared). I have tried to base the condition on SenderName and SenderEmailAddress, but to no avail (reply email gets generated with the contents of the previous email retrieved but the text I intend to put in front of it is not there; the cause is that the value of oReply.SenderEmailAddress is empty as Else clause will write the stuff as intended).
(and yes, there are snippets from code enabling reply with attachments)
Sub ReplyWithAttachments()
Dim oReply As Outlook.MailItem
Dim oItem As Object
Dim sSignature As String
Set oItem = GetCurrentItem()
If Not oItem Is Nothing Then
Set oReply = oItem.Reply
If oReply.SenderEmailAddress = "mailbox.private#something.com" Then
sSignature = "Hello and welcome!"
ElseIf oReply.SenderEmailAddress = "mailbox.shared#something.com" Then
sSignature = "Go to hell!"
End If
CopyAttachments oItem, oReply
oReply.HTMLBody = sSignature & oReply.HTMLBody
oReply.Display
oItem.UnRead = False
End If
Set oReply = Nothing
Set oItem = Nothing
End Sub
Edit:
so I managed to get somewhere with
Set oReply = oItem.Reply
sMailBox = oReply.Sender.GetExchangeUser.Address
If sMailBox = "mailbox.private#something.com" Then
sSignature = "whatever"
ElseIf sMailBox = "mailbox.shared#something.com" Then
sSignature = "bla bla bla"
Else
sSignature = "Something"
The code works as intended for the shared mailbox but for the private one, it errors out with Object variable or With block variable not set pointing to .Sender
sMailBox = oReply.Sender.GetExchangeUser.Address
I have something that I use to get sender email (as its dependent on your email exchange)
Dim strSendersEmailAddress As String
If oItem.SenderEmailType = "EX" Then
strSendersEmailAddress = oItem.Sender.GetExchangeUser.PrimarySmtpAddress
Else
strSendersEmailAddress = oItem.SenderEmailAddress
End If
You will have to get the email address before you Set oReply = oItem.Reply

Auto accept/auto tentative accept

I want to accept or tentatively accept meeting requests in Outlook, depending on whether I have a meeting at that time. I've got the rule set up; it runs the VBA as far as I know, but the code isn't working. I can't find the issue with it.
Sub AcceptDecline(oRequest As MeetingItem)
If oRequest.MessageClass <> "IPM.Schedule.Meeting.Request" Then
Exit Sub 'if this messageclass isn't a meeting request
End If
Dim oAppt As AppointmentItem
Set oAppt = oRequest.GetAssociatedAppointment(True)
Dim myAcct As Outlook.Recipient
Dim myFB As String
Set myAcct = Session.CreateRecipient("roconnor#pattonair.com")
myFB = myAcct.FreeBusy(oAppt.Start, 5, False) 'gets the free or busy status of my calendar
Dim oResponse
Dim i As Long
Dim test As String
i = (TimeValue(oAppt.Start) * 288)
test = Mid(myFB, i - 2, (oAppt.Duration / 5) + 2)
If InStr(1, test, "1") Then
Set oResponse = oAppt.Respond(olMeetingTentative, True)
oResponse.Display
oResponse.Send
Else
Set oResponse = oAppt.Respond(olMeetingAccepted, True)
oResponse.Display
oResponse.Send
End If
End Sub
If the meeting request automatically creates a meeting that is tentatively accepted then free busy indicates you are busy. The response will always be tentative accept.
File-> Options-> Mail-> Tracking-> disable: Automatically process meeting requests and responses to meeting requests and polls
https://www.msoutlook.info/question/do-not-automatically-accept-meeting-as-tentative
If that is not the problem then open the request, which is not automatically marked tentative, and step through with:
Private Sub AcceptDecline_test()
AcceptDecline ActiveInspector.currentItem
End Sub

How to add a second optional object to open Outlook in Access VBA?

So far I have the first referral open-up the Outlook and retrieving the right email address with an automatic customized message. Now, I'm trying to add a second referral, Referral_To_ID_2 as an optional, meaning don't raise error if it isn't selected. Below is the form and the code I have so far, but I'm not quite sure if I'm doing it right by assigning a reference to my second object, Referral_To_ID_2 as well as the If statement. Now it's actually giving me an error if I don't select anything in Referral_To_ID_2 Can anyone explain me the best way to add a second object as an optional? Many thanks!
Private Sub cmdReferralEmail_Click()
Dim emailAddresses As Collection, newEmail As Email
Dim emailAddresses2 As Collection, newEmail2 As Email
Set emailAddresses = GetEmails(referralId:=Referral_To_ID)
Set emailAddresses2 = GetEmails(referralId:=Referral_To_ID_2)
If emailAddresses Is Nothing Then 'User cancelled
ElseIf emailAddresses2 Is Nothing Then 'User cancelled
GoTo ExitHandler
ElseIf emailAddresses.count = 0 Then
MsgBox "No email addresses were selected for this client.", vbExclamation
Else
Set newEmail = New Email
Set newEmail2 = New Email
With newEmail
.HtmlBody = _
"<p>We referred a potential client to you, " & _
Nz(First_Name & " ", "") & Nz(Last_Name, "") & _
", who needs help with an employment matter in " & Nz(State, "your state") & _
". Thank you for any assistance you might be able to provide.</p>"
Set .MailTo = emailAddresses
Set .MailTo = emailAddresses2
.Cc.Add "kjghkjgh#ihiu.com"
.Subject = "Potential"
.Send
End With
End If End Sub
My program reads through a list of people, if they are marked for a Maintenance for example it pulls a query and sets a recordset to that query with:
strSQL = "SELECT Email FROM Employees WHERE '" & department & "' = Department"
Debug.Print strSQL 'I do this so I can see what my query is in the immediate window
Set myR = CurrentDb.OpenRecordset(strSQL)
Then when the recordset has been made, I loop through each record that matched the criteria in the query and add the to the olTo of the email.
Do While Not myR.EOF
Debug.Print myR!Email 'print the email of the record I'm on
Set appOutlookRec = .Recipients.Add(myR!Email)
appOutlookRec.Type = olTo
myR.MoveNext
Loop
But to answer your question more specifically, I would add two IF statements checking first if Referral_To_ID_2 is null.
If Referral_To_ID_2 = Null Then 'or if its a string then If Len(Me.Notes & vbNullString) = 0
'do nothing
Else
Set emailAddresses2 = GetEmails(referralId:=Referral_To_ID_2)
End if
then put the second if down where you Set .MailTo
If emailAddresses2 = Nothing then 'I think that's how that would go, not 100%
'do nothing
Else
Set .MailTo = emailAddresses2
End if
No please know that I'm no guru. I've tried to piece this together with my knowledge I've picked up on so if anyone reads this and can modify it better then have at it. Let me know how it goes.
Because I needed it to open two separate Outlook windows I had to basically copy and paste the code I had for the second referral from the first referral and for the second referral not show error when isn't selected, here is what I came up with and it's working:
If IsNull(Referral_To_ID_2) Then
On Error Resume Next
Else
Set emailAddresses2 = GetEmails(referralId:=Referral_To_ID_2)
End If
Thanks all for your input!