How to export email addresses from outlook meeting request - vba

I sent an outlook (2010) meeting request to all company (4000+) and now I would like to send an additional email to those who accepted the request or accepted tentatively.
How do I do that? When I hit Contact Atendees --> New Email to Atendees in the ribbon it just send a response to all company and not only those who accepted. I also tried to export the contacts but it can only export the name alias and not the entire email addresses.
Any suggestions?
Thanks

The basis of the solution is found here Get Meeting Attendee List Macro
Here it is with minor changes.
Option Explicit
Sub GetAttendeeList()
Dim objApp As Outlook.Application
Dim objItem As Object
Dim objAttendees As Outlook.Recipients
Dim objAttendeeReq As String
Dim objAttendeeOpt As String
Dim objOrganizer As String
Dim dtStart As Date
Dim dtEnd As Date
Dim strSubject As String
Dim strLocation As String
Dim strNotes As String
Dim strMeetStatus As String
Dim strCopyData As String
Dim strCount As String
Dim ino, it, ia, ide
Dim x As Long
Dim ListAttendees As mailitem
'On Error Resume Next
Set objApp = CreateObject("Outlook.Application")
Set objItem = GetCurrentItem()
Set objAttendees = objItem.Recipients
On Error GoTo EndClean:
' Is it an appointment
If objItem.Class <> 26 Then
MsgBox "This code only works with meetings."
GoTo EndClean:
End If
' Get the data
dtStart = objItem.Start
dtEnd = objItem.End
strSubject = objItem.Subject
strLocation = objItem.location
strNotes = objItem.body
objOrganizer = objItem.Organizer
objAttendeeReq = ""
objAttendeeOpt = ""
Set ListAttendees = Application.CreateItem(olMailItem) ' <---
' Get The Attendee List
For x = 1 To objAttendees.count
strMeetStatus = ""
Select Case objAttendees(x).MeetingResponseStatus
Case 0
strMeetStatus = "No Response (or Organizer)"
ino = ino + 1
Case 1
strMeetStatus = "Organizer"
ino = ino + 1
Case 2
strMeetStatus = "Tentative"
it = it + 1
ListAttendees.Recipients.Add objAttendees(x) ' <---
Case 3
strMeetStatus = "Accepted"
ia = ia + 1
ListAttendees.Recipients.Add objAttendees(x) ' <---
Case 4
strMeetStatus = "Declined"
ide = ide + 1
End Select
If objAttendees(x).Type = olRequired Then
objAttendeeReq = objAttendeeReq & objAttendees(x).Name & vbTab & strMeetStatus & vbCrLf
Else
objAttendeeOpt = objAttendeeOpt & objAttendees(x).Name & vbTab & strMeetStatus & vbCrLf
End If
Next
strCopyData = "Organizer: " & objOrganizer & vbCrLf & "Subject: " & strSubject & vbCrLf & _
"Location: " & strLocation & vbCrLf & "Start: " & dtStart & vbCrLf & "End: " & dtEnd & _
vbCrLf & vbCrLf & "Required: " & vbCrLf & objAttendeeReq & vbCrLf & "Optional: " & _
vbCrLf & objAttendeeOpt & vbCrLf & "NOTES " & vbCrLf & strNotes
strCount = "Accepted: " & ia & vbCrLf & _
"Declined: " & ide & vbCrLf & _
"Tentative: " & it & vbCrLf & _
"No response: " & ino
'Set ListAttendees = Application.CreateItem(olMailItem)
ListAttendees.body = strCopyData & vbCrLf & strCount
ListAttendees.Display
ListAttendees.Recipients.ResolveAll ' <---
EndClean:
Set objApp = Nothing
Set objItem = Nothing
Set objAttendees = Nothing
End Sub

Building upon what #niton wrote, I've added support for checking against the Global Address List. This code could be extended to search all address lists available to you by iterating through myAddressLists, however, in most cases, that will probably be more than wanted.
Note that this isn't optimized for speed, but even a list with a few hundred people invited against a GAL of tens of thousands won't take a computer very long to iterate through. Since this doesn't get run very often, the time saved for optimizing this just didn't seem worth it.
Option Explicit
Sub GetAttendeeList()
Dim x As Integer
Dim y As Integer
Dim ino As Integer
Dim it As Integer
Dim ia As Integer
Dim ide As Integer
Dim objApp As Outlook.Application
Dim objItem As Object
Dim objAttendees As Outlook.Recipients
Dim objAttendeeReq As String
Dim objAttendeeOpt As String
Dim strAttendeeName As String
Dim strAttendeeEmail As String
Dim objOrganizer As String
Dim dtStart As Date
Dim dtEnd As Date
Dim strSubject As String
Dim strLocation As String
Dim strNotes As String
Dim strMeetStatus As String
Dim strCopyData As String
Dim strCount As String
Dim strCity As String
Dim folContacts As Outlook.MAPIFolder
Dim oContact As Outlook.ContactItem
Dim colItems As Outlook.Items
Dim oNS As Outlook.NameSpace
Dim ListAttendees As MailItem
Dim strNewRecord As String
Dim myAddressLists As AddressLists
Dim myAddressEntries As AddressEntries
Dim myAddressEntry As AddressEntry
Dim myExchangeUser As ExchangeUser
Dim myExchangeDL As ExchangeDistributionList
Dim myContactItem As ContactItem
On Error Resume Next
Set objApp = CreateObject("Outlook.Application")
Set oNS = Application.GetNamespace("MAPI")
Set folContacts = oNS.GetDefaultFolder(olFolderContacts)
Set colItems = folContacts.Items
Set myAddressLists = oNS.AddressLists
Set myAddressEntries = myAddressLists.Item("Global Address List").AddressEntries
Set objItem = GetCurrentItem()
Set objAttendees = objItem.Recipients
On Error GoTo EndClean:
' Is it an appointment
If objItem.Class <> 26 Then
MsgBox "This code only works with meetings."
GoTo EndClean:
End If
' Get the data
dtStart = objItem.Start
dtEnd = objItem.End
strSubject = objItem.Subject
strLocation = objItem.Location
strNotes = objItem.Body
objOrganizer = objItem.Organizer
objAttendeeReq = ""
objAttendeeOpt = ""
' Get The Attendee List
For x = 1 To objAttendees.Count
strMeetStatus = ""
Select Case objAttendees(x).MeetingResponseStatus
Case 0
strMeetStatus = "No Response (or Organizer)"
ino = ino + 1
Case 1
strMeetStatus = "Organizer"
ino = ino + 1
Case 2
strMeetStatus = "Tentative"
it = it + 1
Case 3
strMeetStatus = "Accepted"
ia = ia + 1
Case 4
strMeetStatus = "Declined"
ide = ide + 1
End Select
strAttendeeName = objAttendees(x).Name
strAttendeeEmail = objAttendees(x).Address
Set oContact = colItems.Find("[Email1Address] = '" & strAttendeeEmail & "'")
If Not oContact Is Nothing Then
Debug.Print "Test", oContact.BusinessAddressCity
strCity = oContact.MailingAddressCity & ", " & oContact.MailingAddressState
End If
If InStr(strAttendeeEmail, "#") = 0 Then
Debug.Print "Searching: " & objAttendees(x).Name
Set myAddressEntry = myAddressEntries.GetFirst()
Do While Not myAddressEntry Is Nothing
If myAddressEntry.Address Like objAttendees(x).Address Then
Debug.Print "Found: " & myAddressEntry.Name
Set myExchangeUser = myAddressEntry.GetExchangeUser()
Set myExchangeDL = myAddressEntry.GetExchangeDistributionList()
Set myContactItem = myAddressEntry.GetContact()
If Not myExchangeUser Is Nothing Then
strAttendeeEmail = myExchangeUser.PrimarySmtpAddress
End If
If Not myExchangeDL Is Nothing Then
strAttendeeEmail = myExchangeDL.PrimarySmtpAddress
End If
If Not myContactItem Is Nothing Then
strAttendeeEmail = myContactItem.Email1Address
End If
GoTo ContactFound
End If
Set myAddressEntry = myAddressEntries.GetNext()
Loop
End If
ContactFound:
strNewRecord = objAttendees(x).Name & vbTab & strAttendeeEmail & vbTab & strMeetStatus & vbTab & strCity & vbCrLf
If objAttendees(x).Type = olRequired Then
objAttendeeReq = objAttendeeReq & strNewRecord
Else
objAttendeeOpt = objAttendeeOpt & strNewRecord
End If
Next
strCopyData = "Organizer: " & objOrganizer & vbCrLf & "Subject: " & strSubject & vbCrLf & _
"Location: " & strLocation & vbCrLf & "Start: " & dtStart & vbCrLf & "End: " & dtEnd & _
vbCrLf & vbCrLf & "Required: " & vbCrLf & objAttendeeReq & vbCrLf & "Optional: " & _
vbCrLf & objAttendeeOpt & vbCrLf & "NOTES " & vbCrLf & strNotes
strCount = "Accepted: " & ia & vbCrLf & _
"Declined: " & ide & vbCrLf & _
"Tentative: " & it & vbCrLf & _
"No response: " & ino
Set ListAttendees = Application.CreateItem(olMailItem)
ListAttendees.Body = strCopyData & vbCrLf & strCount & vbCrLf & Time
ListAttendees.Display
EndClean:
Set objApp = Nothing
Set objItem = Nothing
Set objAttendees = Nothing
End Sub
Function GetCurrentItem() As Object
Dim objApp As Outlook.Application
Set objApp = Application
On Error Resume Next
Select Case TypeName(objApp.ActiveWindow)
Case "Explorer"
Set GetCurrentItem = objApp.ActiveExplorer.Selection.Item(1)
Case "Inspector"
Set GetCurrentItem = objApp.ActiveInspector.CurrentItem
End Select
Set objApp = Nothing
End Function

Related

Looping through unread emails, changing unread to read, using For Each

I wrote code to pick up unread email and with other criteria.
The code runs but For Each itm In olFolder.Items.Restrict(sFilter) is not working.
For example if there are 4 unread emails in the inbox the For Each should loop 4 times but the loop is happening only 2 times.
Sub ReadOutlookEmails_WithCriteria()
Dim olApp As Outlook.Application, olNs As Outlook.Namespace
Dim olFolder As Outlook.MAPIFolder, olMail As Outlook.MailItem
Dim eFolder As Outlook.Folder '~~> additional declaration
Dim Inbox As Outlook.MAPIFolder
Dim SubFolder As Outlook.MAPIFolder
Dim objAtt As Outlook.Attachment
Dim olItem As Outlook.MailItem
Dim olReply As MailItem ' Reply
Dim olRecip As Recipient
Dim i As Long
Dim x As Date, ws As Worksheet '~~> declare WS variable instead
Dim lrow As Long '~~> additional declaration
Set ws = ActiveSheet '~~> or you can be more explicit using the next line
Set EC = ThisWorkbook.Sheets("Email Search Criteria")
Set IE = ThisWorkbook.Sheets("Inbox Emails")
Set olApp = New Outlook.Application
Set olNs = olApp.GetNamespace("MAPI")
Set Inbox = olNs.GetDefaultFolder(olFolderInbox)
Set SubFolder = Inbox.Folders("Rejected Emails")
Todays_Date = EC.Range("E2").Value
IE.Rows("2:10000").Clear
Incr = 2
For Each eFolder In olNs.GetDefaultFolder(olFolderInbox).Folders
If eFolder = "Mandatory Training Enrollment" Then 'IF_Check_1
Set olFolder = olNs.GetDefaultFolder(olFolderInbox).Folders(eFolder.Name): Debug.Print olFolder
sFilter = "[ReceivedTime] >= '" & Todays_Date & "' AND [UNREAD]=TRUE"
Debug.Print olFolder.Items.Restrict(sFilter).Count
'>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
For Each itm In olFolder.Items.Restrict(sFilter) ''''Problem is over here
'>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
If itm.Attachments.Count = EC.Range("B2") Then 'itm Like "*" & EC.Range("A2") & "*" And'IF_Check_2
For Each objAtt In itm.Attachments
Debug.Print "Subject Name - " & itm: Debug.Print "Attachment Type - " & objAtt.DisplayName
Debug.Print "Attachment Size - " & objAtt.Size: Debug.Print "Attachments Count - " & objAtt.Index
Debug.Print "Subject Name - " & EC.Range("A2"): Debug.Print "Attachment Type - " & EC.Range("C2")
Debug.Print "Attachment Size - " & EC.Range("D2"): Debug.Print "Attachments Count - " & EC.Range("B2")
If objAtt.Size <= EC.Range("D2") And UCase(objAtt.Filename) Like UCase("*" & EC.Range("C2")) Then
IE.Range("A" & Incr) = olFolder
IE.Range("B" & Incr) = itm.SenderName
IE.Range("C" & Incr) = itm
IE.Range("D" & Incr) = objAtt.DisplayName
IE.Range("E" & Incr) = itm.Attachments.Count
IE.Range("F" & Incr) = objAtt.Size
IE.Range("G" & Incr) = "Pass"
Set olReply = itm.ReplyAll
'Set olRecip = olReply.Recipients.Add("Email Address Here") ' Recipient Address
'olRecip.Type = olCC
olReply.Body = "Hello," & vbNewLine & vbNewLine & "Email Success" & vbNewLine & vbNewLine & "Thank you. " & vbCrLf & olReply.Body
olReply.Display
'olReply.SentOnBehalfOfName = onBehalfOf
'olReply.SendUsingAccount = getGenericMailboxAccount(onBehalfOf)
olReply.Send
itm.UnRead = False
End If
Next objAtt
ElseIf itm.Attachments.Count <> EC.Range("B2") Then 'IF_Check_2
FailReason1 = "Attament is not a PDF"
FailReason2 = "Attachment size is more than 10MB"
FailReason3 = "Attachment is missing with email"
FailReason4 = "Attachments are more than 1"
IE.Range("A" & Incr) = olFolder
IE.Range("B" & Incr) = itm.SenderName
IE.Range("C" & Incr) = itm
IE.Range("D" & Incr) = ""
IE.Range("E" & Incr) = itm.Attachments.Count
IE.Range("F" & Incr) = ""
IE.Range("G" & Incr) = "Fail"
EBody = "Hello," & vbNewLine & vbNewLine & "Email Not Success." & vbNewLine & vbNewLine _
& "Fail Reason Might Be One Of The Below Mentioned:" & vbNewLine & vbNewLine _
& "*" & FailReason1 & vbNewLine & vbNewLine _
& "*" & FailReason2 & vbNewLine & vbNewLine _
& "*" & FailReason3 & vbNewLine & vbNewLine _
& "*" & FailReason4 & vbNewLine & vbNewLine _
Set olReply = itm.ReplyAll
'Set olRecip = olReply.Recipients.Add("Email Address Here") ' Recipient Address
'olRecip.Type = olCC
'olReply.Body = "Hello," & vbCrLf & "Email Not Success" & vbCrLf & FailReason1 & vbCrLf & FailReason2 & vbCrLf & FailReason3 & vbCrLf & olReply.Body
olReply.Body = EBody & vbCrLf & olReply.Body
olReply.Display
'olReply.SentOnBehalfOfName = onBehalfOf
'olReply.SendUsingAccount = getGenericMailboxAccount(onBehalfOf)
olReply.Send
itm.UnRead = False
itm.Move SubFolder
End If 'IF_Check_2
Incr = Incr + 1
'>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Next itm ' Its passing to the next statement even though loop is not completed.
'>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
Set olFolder = Nothing
End If ''IF_Check_1
Next eFolder
End Sub
Your are modifying (by setting the Unread property to false) the very collection you are iterating over.
Do not use foreach - use a down loop.
set restrItems = olFolder.Items.Restrict(sFilter)
For i = restrItems.Count to 1 Step -1
set itm = restrItems(i)
First of all, you need to make sure the date object is formatted in the way Outlook understands:
sFilter = "[ReceivedTime] >= '" & Todays_Date & "' AND [UNREAD]=TRUE"
Use the Format function available in VBA.
sFilter = "[ReceivedTime] > '" & Format(Todays_Date, "ddddd h:nn AMPM") & "'"

Is it possible to identify through OUTLOOK triggers/events to which shared mail box has received a new email?

We are trying to store new mail item components into excel and assign tkt id, have tried doing it with single shared mailbox and succeeded but we want to implement same for 20 shared mail boxes. how can outlook vba event/trigger identify as soon as new email arrives to one of the 20 shared mail boxes.
this is code which will only work for default inbox:
Private Sub inboxItems_ItemAdd(ByVal Item As Object)
Dim Msg As Outlook.MailItem
Dim MessageInfo
Dim Result
If TypeName(Item) = "MailItem" Then
Dim cn As Object
Dim sCon As String
Dim sSQL As String
Dim bytHasAttachment As String
Dim strAddress As String
Dim objSender, exUser
Dim olRecipient As Outlook.Recipient
Dim strToEmails, strCcEmails, strBCcEmails As String
For Each olRecipient In Item.Recipients
Dim mail As String
If olRecipient.AddressEntry Is Nothing Then
mail = olRecipient.Address
ElseIf olRecipient.AddressEntry.GetExchangeUser Is Nothing Then
mail = olRecipient.Address
Else
mail = olRecipient.AddressEntry.GetExchangeUser.PrimarySmtpAddress
End If
If olRecipient.Type = Outlook.OlMailRecipientType.olTo Then
strToEmails = strToEmails + mail & ";"
ElseIf olRecipient.Type = Outlook.OlMailRecipientType.olCC Then
strCcEmails = strCcEmails + mail & ";"
ElseIf olRecipient.Type = Outlook.OlMailRecipientType.olBCC Then
strBCcEmails = strBCcEmails + mail & ";"
End If
Next
With Item
If Item.Attachments.Count > 0 Then
bytHasAttachment = 1
Else
bytHasAttachment = 0
End If
End With
'On Error Resume Next 'PropertyAccessor can raise an exception if a property is not found
If Item.SenderEmailType = "SMTP" Then
strAddress = Item.SenderEmailAddress
Else
'read PidTagSenderSmtpAddress
strAddress = Item.PropertyAccessor.GetProperty("http://schemas.microsoft.com/mapi/proptag/0x5D01001F")
If Len(strAddress) = 0 Then
Set objSender = Item.Sender
If Not (objSender Is Nothing) Then
'read PR_SMTP_ADDRESS_W
strAddress = objSender.PropertyAccessor.GetProperty("http://schemas.microsoft.com/mapi/proptag/0x39FE001F")
If Len(strAddress) = 0 Then
Set exUser = objSender.GetExchangeUser
If Not (exUser Is Nothing) Then
strAddress = exUser.PrimarySmtpAddress
End If
End If
End If
End If
End If
On Error GoTo ErrorHandler
Set cn = CreateObject("ADODB.Connection")
sCon = "Driver=MySQL ODBC 8.0 ANSI Driver;SERVER=localhost;UID=root;PWD={Platinum#123};DATABASE=liva_dev_gm;PORT=3306;COLUMN_SIZE_S32=1;DFLT_BIGINT_BIND_STR=1"
cn.Open sCon
sSQL = "INSERT INTO tbl_gmna_emailmaster_inbox (eMail_Icon, eMail_MessageID, eMail_Folder, eMail_Act_Subject, eMail_From, eMail_TO, eMail_CC, " & _
"eMail_BCC, eMail_Body, eMail_DateReceived, eMail_TimeReceived, eMail_Anti_Post_Meridiem, eMail_Importance, eMail_HasAttachment) " & _
"VALUES (""" & Item.MessageClass & """, " & _
"""" & Item.EntryID & """, " & _
"""Inbox""" & ", " & _
"""" & Item.Subject & """, " & _
"""" & strAddress & """, " & _
"""" & strToEmails & """, " & _
"""" & strCcEmails & """, " & _
"""" & strBCcEmails & """, " & _
"""" & Item.Body & """, " & "'" & Format(Item.ReceivedTime, "YYYY-MM-DD") & "', " & "'" & Format(Item.ReceivedTime, "hh:mm:ss") & "', " & "'" & Format(Item.ReceivedTime, "am/pm") & "', " & "'" & Item.Importance & "', " & "'" & bytHasAttachment & "')"
cn.Execute sSQL
End If
ExitNewItem:
bytHasAttachment = ""
Exit Sub
ErrorHandler:
MsgBox Err.Number & " - " & Err.Description
Resume ExitNewItem
End Sub
If the 20 shared mailboxes are in the navigation pane.
Option Explicit
Private WithEvents inboxItms As Items
Private WithEvents sharedInboxItms1 As Items
' ...
Private WithEvents sharedInboxItms20 As Items
Private Sub Application_Startup()
Dim defaultInbox As Folder
Dim sharedMailbox1 As Folder
Dim sharedInbox1 As Folder
' ...
Dim sharedMailbox20 As Folder
Dim sharedInbox20 As Folder
Set defaultInbox = Session.GetDefaultFolder(olFolderInbox)
Set inboxItms = defaultInbox.Items
Set sharedMailbox1 = Session.Folders("SharedMailbox1#somewhere.com")
Set sharedInbox1 = sharedMailbox1.Folders("Inbox")
' typo fixed
'Set sharedInboxItms1 = sharedInbox1.Folders("Inbox").Items
Set sharedInboxItms1 = sharedInbox1.Items
' ...
Set sharedMailbox20 = Session.Folders("SharedMailbox20#somewhere.com")
Set sharedInbox20 = sharedMailbox20.Folders("Inbox")
' typo fixed
'Set sharedInboxItms20 = sharedInbox20.Folders("Inbox").Items
Set sharedInboxItms20 = sharedInbox20.Items
End Sub
Private Sub inboxItms_ItemAdd(ByVal Item As Object)
' current code for default inbox
End Sub
Private Sub sharedInboxItms1_ItemAdd(ByVal Item As Object)
inboxItms_ItemAdd Item
End Sub
' ...
Private Sub sharedInboxItms20_ItemAdd(ByVal Item As Object)
inboxItms_ItemAdd Item
End Sub

How do I count meeting participants before adding another in Outlook

How do i count the total participants of a meeting before adding another and sending it?
I've managed to automate calendar invites based on specific responses.
I now need to set a max number of participants and respond with a mail if the maximum number of participants for that meeting or event has been reached.
It seems to stay on "1" if i check the value.
This is as far as i've been able to come without reaching out for help on it.
Private Sub objNewMailItems_ItemAdd(ByVal Item As Object)
Dim objMeetingInvitation As Outlook.MeetingItem
Dim objMeeting As Outlook.AppointmentItem
Dim objAttendees As Outlook.Recipients
Dim objAttendee As Outlook.Recipient
Dim lRequiredAttendeeCount, lOptionalAttendeeCount, lResourceCount As Long
Dim strMsg As String
Dim nPrompt As Integer
On Error Resume Next
Dim olMailItem As MailItem
Dim strAttachementName As String
Dim oRespond As Outlook.MailItem
Dim mesgBody As String
Dim oApp As Outlook.Application
Dim oCalFolder As Outlook.MAPIFolder
Dim oAppt As Outlook.AppointmentItem
Dim sOldText As String
Dim sNewText As String
Dim iCalChangedCount As Integer
Dim mail As Outlook.MailItem
Set oApp = Outlook.Application
Dim nmSpace As Outlook.NameSpace
Set nmSpace = oApp.GetNamespace("MAPI")
Set oCalFolder = nmSpace.GetDefaultFolder(olFolderCalendar)
If TypeOf Item Is MailItem Then
Set olMailItem = Item
Set objMeetingInvitation = Item
Set objMeeting = objMeetingInvitation.GetAssociatedAppointment(True)
Set objAttendees = objMeetingInvitation.Recipients
lRequiredAttendeeCount = 0
lOptionalAttendeeCount = 0
lResourceCount = 0
'Count the required & optional attendees and resources, etc.
'===============================================================================================================
' Please note...
'
' I used mailto:jakes#******.co.za?subject=Yes,%20please%20include%20me&body=I%20would%20like%20to%20join
' as a "mailto:" response
'
'===============================================================================================================
If InStr(olMailItem.Subject, "Testing the Calendar") > 0 Then
sOldText = "Test Calendar"
For Each objAttendee In objAttendees
If objAttendee.Type = olRequired Then
lRequiredAttendeeCount = lRequiredAttendeeCount + 1
ElseIf objAttendee.Type = olOptional Then
lOptionalAttendeeCount = lOptionalAttendeeCount + 1
ElseIf objAttendee.Type = olResource Then
lResourceCount = lResourceCount + 1
End If
Next
If lRequiredAttendeeCount > 1 Then
MsgBox "Attendees on list too many :" & lRequiredAttendeeCount, vbOKOnly
Exit Sub
End If
Do
If Not (oCalFolder Is Nothing) Then
If (oCalFolder.DefaultItemType = olAppointmentItem) Then Exit Do
End If
'MsgBox ("Please select a calendar folder from the following list.")
'Set oCalFolder = GetDefaultFolder(olFolderCalendar)
On Error GoTo ErrHandler:
Loop Until oCalFolder.DefaultItemType = olAppointmentItem
' Loop through appointments in calendar, change text where necessary, keep count
iCalChangedCount = 0
For Each oAppt In oCalFolder.Items
If InStr(oAppt.Subject, sOldText) <> 0 Then
Debug.Print "Changed: " & oAppt.Subject & " - " & oAppt.Start
oAppt.Recipients.Add (olMailItem.SenderEmailAddress)
'oAppt.Display
oAppt.Save
oAppt.Send
iCalChangedCount = iCalChangedCount + 1
End If
Next
' Display results and clear table
MsgBox (iCalChangedCount & " appointments have been updated. You have " & lRequiredAttendeeCount & "attendees.")
Set oAppt = Nothing
Set oCalFolder = Nothing
Exit Sub
End If
ErrHandler:
MsgBox ("Macro terminated.")
End If
Set Item = Nothing
Set olMailItem = Nothing
End Sub
I've been able to count the participants with this but i'm lost trying to combine the two...
Private Sub Application_ItemSend(ByVal Item As Object, Cancel As Boolean)
Dim objMeetingInvitation As Outlook.MeetingItem
Dim objMeeting As Outlook.AppointmentItem
Dim objAttendees As Outlook.Recipients
Dim objAttendee As Outlook.Recipient
Dim lRequiredAttendeeCount, lOptionalAttendeeCount, lResourceCount As Long
Dim strMsg As String
Dim nPrompt As Integer
If TypeOf Item Is MeetingItem Then
Set objMeetingInvitation = Item
Set objMeeting = objMeetingInvitation.GetAssociatedAppointment(True)
Set objAttendees = objMeetingInvitation.Recipients
End If
lRequiredAttendeeCount = 0
lOptionalAttendeeCount = 0
lResourceCount = 0
'Count the required & optional attendees and resources, etc.
For Each objAttendee In objAttendees
If objAttendee.Type = olRequired Then
lRequiredAttendeeCount = lRequiredAttendeeCount + 1
ElseIf objAttendee.Type = olOptional Then
lOptionalAttendeeCount = lOptionalAttendeeCount + 1
ElseIf objAttendee.Type = olResource Then
lResourceCount = lResourceCount + 1
End If
Next
'Double check the meeting invitation details
strMsg = "Meeting Details:" & vbCrLf & vbCrLf & _
"Required Attendees: " & lRequiredAttendeeCount & vbCrLf & _
"Optional Attendees: " & lOptionalAttendeeCount & vbCrLf & _
"Resources: " & lResourceCount & vbCrLf & _
"Duration: " & GetDuration(objMeeting) & vbCrLf & vbCrLf & _
"Are you sure to send this meeting invitation?"
nPrompt = MsgBox(strMsg, vbExclamation + vbYesNo, "Double Check Meeting Invitation")
If nPrompt = vbYes Then
Cancel = False
Else
Cancel = True
End If
End Sub
Any ideas at all will be appreciated!
I believe the question is too broad and could be split into at least three separate questions. Focusing on "How do I count the total participants of a meeting" without the adding and sending part.
I have to assume you run the code when a response arrives.
Option Explicit
Private Sub objNewMailItems_ItemAdd_Test()
' first open up a response to a meeting invitation
objNewMailItems_ItemAdd ActiveInspector.currentItem
End Sub
Private Sub objNewMailItems_ItemAdd(ByVal Item As Object)
Dim oAppt As AppointmentItem
Dim objAttendees As Recipients
Dim objAttendee As Recipient
Dim lRequiredAttendeeCount As Long
Dim lOptionalAttendeeCount As Long
Dim lResourceCount As Long
Dim possibleAttendees As Long
Dim limitedAtendees As Long
' For testing purposes
limitedAtendees = InputBox(Prompt:="Enter the maximum number of invitations allowed", Default:="2")
'limitedAtendees = some maximum
' Kiss of death removed
'On Error Resume Next
If TypeOf Item Is MeetingItem Then
' Bypass one error only, for a specific purpose
On Error Resume Next
Set oAppt = Item.GetAssociatedAppointment(True)
' Turn off bypass
On Error GoTo 0
If oAppt Is Nothing Then
MsgBox "No associated appointment found."
Exit Sub
End If
Set objAttendees = oAppt.Recipients
'Debug.Print objAttendees.count
lRequiredAttendeeCount = 0
lOptionalAttendeeCount = 0
lResourceCount = 0
'Count the required & optional attendees and resources, etc.
For Each objAttendee In objAttendees
'Debug.Print objAttendee
If objAttendee.Type = olRequired Then
lRequiredAttendeeCount = lRequiredAttendeeCount + 1
'ElseIf objAttendee.Type = olOptional Then
' lOptionalAttendeeCount = lOptionalAttendeeCount + 1
'ElseIf objAttendee.Type = olResource Then
' lResourceCount = lResourceCount + 1
End If
Next
If lRequiredAttendeeCount > limitedAtendees Then
MsgBox "Invitations to Required Atendees: " & lRequiredAttendeeCount & vbCr & _
"This is more than the limit of.......: " & limitedAtendees, vbOKOnly
Else
MsgBox "Invitations to Required Atendees: " & lRequiredAttendeeCount & vbCr & _
"This is within the limit of...........: " & limitedAtendees, vbOKOnly
End If
If objAttendees.count > limitedAtendees Then
MsgBox "Invitations to All Atendees..: " & objAttendees.count & vbCr & _
"This is more than the limit of: " & limitedAtendees, vbOKOnly
Else
MsgBox "Invitations to All Atendees: " & lRequiredAttendeeCount & vbCr & _
"This is within the limit of....: " & limitedAtendees, vbOKOnly
End If
End If
ExitRoutine:
Set oAppt = Nothing
End Sub
Edit 2071010
The code in the question points to a count of invitations but appears you need a count of responses.
Private Sub objNewMailItems_ItemAdd(ByVal Item As Object)
Dim objAppt As AppointmentItem
Dim objAttendee As Recipient
Dim lOrganizerAttendeeCount As Long
Dim lRequiredAttendeeCount As Long
Dim lOptionalAttendeeCount As Long
Dim lResourceCount As Long
Dim attendeeOrganizerNoneCount As Long
Dim attendeeAcceptedCount As Long
Dim attendeeTentativeCount As Long
Dim attendeeDeclinedCount As Long
Dim attendeeNotRespondedCount As Long
Dim invitedAttendees As Long
Dim respondingAttendees As Long
Dim uPrompt As String
Dim uTitle As String
Debug.Print
Debug.Print "Item.Class: " & Item.Class
' 26 - AppointmentItem
'
' Various MeetingItems
' 53 to 57
' 53 - should be the initial invitation
' 181 - Meeting Forward Notification
' - with no response (0), the invited person counts as a "None" response
If Item.Class = 26 Then
Set objAppt = Item
' tested
' olMeetingResponsePositive
' 53
' 181
ElseIf Item.Class = olMeetingResponsePositive Or _
Item.Class = olMeetingResponseTentative Or _
Item.Class = olMeetingResponseNegative Or _
Item.Class = 53 Or _
Item.Class = 54 Or _
Item.Class = 55 Or _
Item.Class = 56 Or _
Item.Class = 57 Or _
Item.Class = 181 Then
' Bypass errors for a specific purpose
On Error Resume Next
Set objAppt = Item.GetAssociatedAppointment(True)
' Turn error bypass off
On Error GoTo 0
If objAppt Is Nothing Then
MsgBox "No appointment associated with the meeting response " & _
vbCr & vbCr & Item.Subject
Exit Sub
End If
Else
MsgBox "Item class " & Item.Class & " not recognized in this code. "
Exit Sub
End If
For Each objAttendee In objAppt.Recipients
Debug.Print
Debug.Print "Invitee name...: " & objAttendee.name
'Count the invitations
Debug.Print "Invitation Type: " & objAttendee.Type
' https://msdn.microsoft.com/en-us/vba/outlook-vba/articles/olmeetingrecipienttype-enumeration-outlook
' 0 = olOrganizer
' 1 = olRequired
' 2 = olOptional
' 3 = olResource
Select Case objAttendee.Type
Case 0
lOrganizerAttendeeCount = lOrganizerAttendeeCount + 1
Case 1
lRequiredAttendeeCount = lRequiredAttendeeCount + 1
Case 2
lOptionalAttendeeCount = lOptionalAttendeeCount + 1
Case 3
lResourceCount = lResourceCount + 1
End Select
' Count the responses
Debug.Print "Response Status: " & objAttendee.MeetingResponseStatus
' https://msdn.microsoft.com/VBA/Outlook-VBA/articles/olresponsestatus-enumeration-outlook
' 0 = "None" - This is what I get as the organizer
' 1 = "Organized"
' 2 = "Tentative"
' 3 = "Accepted"
' 4 = "Declined"
' 5 = "Not Responded"
Select Case objAttendee.MeetingResponseStatus
Case 0
attendeeOrganizerNoneCount = attendeeOrganizerNoneCount + 1
Case 1
attendeeOrganizerNoneCount = attendeeOrganizerNoneCount + 1
Case 2
attendeeTentativeCount = attendeeTentativeCount + 1
Case 3
attendeeAcceptedCount = attendeeAcceptedCount + 1
Case 4
attendeeDeclinedCount = attendeeDeclinedCount + 1
Case 5
attendeeNotRespondedCount = attendeeNotRespondedCount + 1
End Select
Set objAttendee = Nothing
Next
invitedAttendees = lOrganizerAttendeeCount + lRequiredAttendeeCount + _
lOptionalAttendeeCount + lResourceCount
respondingAttendees = attendeeOrganizerNoneCount + attendeeAcceptedCount + _
attendeeTentativeCount + attendeeDeclinedCount + attendeeNotRespondedCount
' Display results
uTitle = "Attendees for " & objAppt.Subject
uPrompt = "Invitations:" & vbCr & _
" " & lOrganizerAttendeeCount & " :Organizer" & vbCr & _
" " & lRequiredAttendeeCount & " :Required" & vbCr & _
" " & lOptionalAttendeeCount & " :Optional" & vbCr & _
" " & lResourceCount & " :Resource" & vbCr & _
" " & invitedAttendees & " : TOTAL" & vbCr & vbCr
uPrompt = uPrompt & " Responses:" & vbCr & _
" " & attendeeOrganizerNoneCount & " :organizer none" & vbCr & _
" " & attendeeAcceptedCount & " :accepts" & vbCr & _
" " & attendeeTentativeCount & " :tentatives" & vbCr & _
" " & attendeeDeclinedCount & " :declines" & vbCr & _
" " & attendeeNotRespondedCount & " :no responses" & vbCr & _
" " & respondingAttendees & " : TOTAL"
MsgBox Prompt:=uPrompt, Title:=uTitle
ExitRoutine:
Set objAppt = Nothing
Set objAttendee = Nothing
End Sub

Error 440 "Array Index out of Bounds"

I am trying to download an Excel attachment with the subject keyword.
I managed to create a code but sometimes it is giving Error 440 "Array Index out of Bounds".
The code got stuck in this part.
If Items(i).Class = Outlook.OlObjectClass.OlMail Then
Here is the code
Sub Attachment()
Dim N1 As String
Dim En As String
En = CStr(Environ("USERPROFILE"))
saveFolder = En & "\Desktop\"
N1 = "Mail Attachment"
If Len(Dir(saveFolder & N1, vbDirectory)) = 0 Then
MkDir (saveFolder & N1)
End If
Call Test01
End Sub
Private Sub Test01()
Dim Inbox As Outlook.Folder
Dim obj As Object
Dim Items As Outlook.Items
Dim Attach As Object
Dim MailItem As Outlook.MailItem
Dim i As Long
Dim Filter As String
Dim saveFolder As String, pathLocation As String
Dim dateFormat As String
Dim dateCreated As String
Dim strNewFolderName As String
Dim Creation As String
Const Filetype1 As String = "xlsx"
Const Filetype2 As String = "xlsm"
Const Filetype3 As String = "xlsb"
Const Filetype4 As String = "xls"
Dim Env As String
Env = CStr(Environ("USERPROFILE"))
saveFolder = Env & "\Desktop\Mentor Training\"
Set Inbox = Application.GetNamespace("MAPI").GetDefaultFolder(olFolderInbox)
'If Inbox.Items.Restrict("[UnRead] = True").Count = 0 Then
' MsgBox "No Mentor Training Mail In Inbox"
' Exit Sub
'End If
Filter = "#SQL=" & Chr(34) & "urn:schemas:httpmail:datereceived" & _
Chr(34) & " >= '4/2/2017' AND " & _
Chr(34) & "urn:schemas:httpmail:hasattachment" & _
Chr(34) & "=1 AND" & Chr(34) & _
Chr(34) & "urn:schemas:httpmail:read" & _
Chr(34) & "= 0"
Set Items = Inbox.Items.Restrict(Filter)
For i = 1 To Items.Count
If Items(i).Class = Outlook.OlObjectClass.olMail Then
Set obj = Items(i)
Debug.Print obj.subject
For Each Attach In obj.Attachments
If Right(LCase(Attach.fileName), Len(Filetype1)) = Filetype1 Then 'For searching only excel files
dateFormat = Format(obj.ReceivedTime(), "dd-mm-yyyy hh-mm")
Attach.SaveAsFile saveFolder & "(" & dateFormat & ")" & " " & Attach
End If
If Right(LCase(Attach.fileName), Len(Filetype2)) = Filetype2 Then 'For searching only excel files
dateFormat = Format(obj.ReceivedTime(), "dd-mm-yyyy hh-mm")
Attach.SaveAsFile saveFolder & "(" & dateFormat & ")" & " " & Attach
End If
If Right(LCase(Attach.fileName), Len(Filetype3)) = Filetype3 Then 'For searching only excel files
dateFormat = Format(obj.ReceivedTime(), "dd-mm-yyyy hh-mm")
Attach.SaveAsFile saveFolder & "(" & dateFormat & ")" & " " & Attach
End If
If Right(LCase(Attach.fileName), Len(Filetype4)) = Filetype4 Then 'For searching only excel files
dateFormat = Format(obj.ReceivedTime(), "dd-mm-yyyy hh-mm")
Attach.SaveAsFile saveFolder & "(" & dateFormat & ")" & " " & Attach
End If
obj.UnRead = False
DoEvents
obj.Save
Next
End If
Next
MsgBox "Attachment Saved"
End Sub
It was my understanding that arrays in vba started at 0 by default. So if there is only one item in the list it will be located at Items(0). And since your for statement starts by looking at Items(1) it will throw that error. Changing it to:
For i = 0 To Items.Count - 1
should work I believe.
The filter may return zero items.
Set Items = Inbox.Items.Restrict(Filter)
If Items.Count > 0 then
For i = 1 To Items.Count
No need for setting up multiple dot objects simply use
If Items(i).Class = olMail Then
You may also wanna set your objects to nothing, once your done with them...
Set Inbox = Nothing
Set obj = Nothing
Set Items = Nothing
Set Attach = Nothing
Set MailItem = Nothing
End Sub

Access VBA To Send Query Results to Outlook Email in Table Format

I would like to send an e-mail with outlook based on the query results from my table but with table formatting (in the body). For some reason the code is only outputting the last record in the table to the e-mail body, instead of looping and adding all 3 records.
Any suggestions, or a better way to code this?
Public Sub NewEmail()
'On Error GoTo Errorhandler
Dim olApp As Object
Dim olItem As Variant
Dim olatt As String
Dim olMailTem As Variant
Dim strSendTo As String
Dim strMsg As String
Dim strTo As String
Dim strcc As String
Dim rst As DAO.Recordset
Dim rs As DAO.Recordset
Dim db As DAO.Database
Dim qry As DAO.QueryDef
Dim fld As Field
Dim varItem As Variant
Dim strtable As String
Dim rec As DAO.Recordset
Dim strqry As String
strqry = "SELECT * From Email_Query"
strSendTo = "test#email.com"
strTo = ""
strcc = ""
Set olApp = CreateObject("Outlook.application")
Set olItem = olApp.CreateItem(olMailTem)
olItem.Display
olItem.To = strTo
olItem.CC = strcc
olItem.Body = ""
olItem.Subject = "Test E-mail"
Set db = CurrentDb
Set rec = CurrentDb.OpenRecordset(strqry)
If Not (rec.BOF And rec.EOF) Then
rec.MoveLast
rec.MoveFirst
intCount = rec.RecordCount
For intLoop = 1 To intCount
olItem.HTMLBody = "<HTML><body>" & _
"<table border='2'>" & _
"<tr>" & _
"<th> Request Type </th>" & _
"<th> ID </th>" & _
"<th> Title </th>" & _
"<th> Requestor Name </th>" & _
"<th> Intended Audience </th>" & _
"<th> Date of Request</th>" & _
"<th> Date Needed </th>" & _
"</tr>" & _
"<tr>" & _
"<td>" & rec("Test1") & "</td>" & _
"<td>" & rec("Test2") & "</td>" & _
"<td>" & rec("Test3") & "</td>" & _
"<td>" & rec("Test4") & "</td>" & _
"<td>" & rec("Test5") & "</td>" & _
"<td>" & rec("Test6") & "</td>" & _
"<td>" & rec("Test7") & "</td>" & _
"</tr>" & _
"<body><HTML>"
rec.MoveNext
Next intLoop
End If
MsgBox "E-mail Sent"
Set olApp = Nothing
Set olItem = Nothing
Exit_Command21_Click:
Exit Sub
ErrorHandler:
MsgBox Err.Description, , Err.Number
Resume Exit_Command21_Click
End Sub
You're changing the HTMLBody every loop rather than adding to it. You should set your header row above the loop, then set each row inside the loop. I like to fill up arrays and use the Join function - it's more visually pleasing to me.
Public Sub NewEmail()
Dim olApp As Object
Dim olItem As Variant
Dim db As DAO.Database
Dim rec As DAO.Recordset
Dim strQry As String
Dim aHead(1 To 7) As String
Dim aRow(1 To 7) As String
Dim aBody() As String
Dim lCnt As Long
'Create the header row
aHead(1) = "Request Type"
aHead(2) = "ID"
aHead(3) = "Title"
aHead(4) = "Requestor Name"
aHead(5) = "Intended Audience"
aHead(6) = "Date of Request"
aHead(7) = "Date Needed"
lCnt = 1
ReDim aBody(1 To lCnt)
aBody(lCnt) = "<HTML><body><table border='2'><tr><th>" & Join(aHead, "</th><th>") & "</th></tr>"
'Create each body row
strQry = "SELECT * From Email_Query"
Set db = CurrentDb
Set rec = CurrentDb.OpenRecordset(strQry)
If Not (rec.BOF And rec.EOF) Then
Do While Not rec.EOF
lCnt = lCnt + 1
ReDim Preserve aBody(1 To lCnt)
aRow(1) = rec("Test1")
aRow(2) = rec("Test2")
aRow(3) = rec("Test3")
aRow(4) = rec("Test4")
aRow(5) = rec("Test5")
aRow(6) = rec("Test6")
aRow(7) = rec("Test7")
aBody(lCnt) = "<tr><td>" & Join(aRow, "</td><td>") & "</td></tr>"
rec.MoveNext
Loop
End If
aBody(lCnt) = aBody(lCnt) & "</table></body></html>"
'create the email
Set olApp = CreateObject("Outlook.application")
Set olItem = olApp.CreateItem(0)
olItem.display
olItem.To = "example#example.com"
olItem.Subject = "Test E-mail"
olItem.htmlbody = Join(aBody, vbNewLine)
olItem.display
End Sub