Emailing through Excel table - vba

I am attempting to email to all email addresses in a table, with the subject line being the corresponding order number or numbers.
The Table has Five columns - "Line Number", "Order Number", "Suppler/Manf.Item Number", "Supplier Name" and "Email Address"
There can be duplicates, but the subject must contain each PO only once.
No CC, or BCC is required
The Body of the Email is to list the PO's with their associated line items.
Hello, We require an update as to the following:
EX
PO86001763
Line Item 2
Line Item 1
Please Send an update as to the status of these line items.
Providing the following: Packing Slips, Tracking Numbers and Updated Ship Dates.
(These being able to be edited would be a boon)
The table is made from an import and format macro, it will always be in the same format, but will contain different data. The amount of data can increase or decrease depending on the week.
Here is my attempt.
Private Sub CommandButton2_Click()
Dim subjectLine As String
Dim bodyline As String
Dim tb As ListObject
Dim lineCounter As Long
Dim myArray1, arrayCounter As Long, tempNumb As Long
Dim nameCounter As Long
Dim emAddress As String
ReDim myArray1(1 To 1)
arrayCounter = 0
nameCounter = 1
Dim I As Integer
Dim X As Integer
Dim C As Object
Dim firstaddress As Variant
Dim Nrow As Boolean
Set tb = ActiveSheet.ListObjects("Table10")
For I = 1 To ActiveSheet.ListObjects("Table10").ListRows.Count
emAddress = tb.DataBodyRange.Cells(I, tb.ListColumns("Email Address").Index)
For X = LBound(myArray1) To UBound(myArray1)
On Error Resume Next
If emAddress = myArray1(X) Then GoTo goToNext
Next X
On Error GoTo 0
subjectLine = "Order(s) # "
ReDim Preserve myArray1(1 To nameCounter)
myArray1(nameCounter) = emAddress
nameCounter = nameCounter + 1
lineCounter = 1
With tb.ListColumns("Email Address").Range
Set C = .Find(emAddress, LookIn:=xlValues)
If Not C Is Nothing Then
firstaddress = C.Address
Beep
arrayCounter = arrayCounter + 1
Do
Nrow = C.Row - 1
If lineCounter = 1 Then
subjectLine = subjectLine & tb.DataBodyRange.Cells (Nrow, tb.ListColumns("Order Number").Index)
lineCounter = lineCounter + 1
bodyline = "Order " & tb.DataBodyRange.Cells(Nrow, tb.ListColumns("Order Number").Index) & ", Line Number " & tb.DataBodyRange.Cells(Nrow, tb.ListColumns("Line Number").Index)
Else:
subjectLine = subjectLine & ", " & tb.DataBodyRange.Cells(Nrow, tb.ListColumns("Order Number").Index)
bodyline = bodyline & vbNewLine & "Order " & tb.DataBodyRange.Cells(Nrow, tb.ListColumns("Order Number").Index) & ", Line Number " & tb.DataBodyRange.Cells(Nrow, tb.ListColumns("Line Number").Index)
End If
Set C = .FindNext(C)
Loop While Not C Is Nothing And C.Address <> firstaddress
End If
Run SendMailFunction(emAddress, subjectLine, bodyline)
' Debug.Print vbNewLine
' Debug.Print emAddress
' Debug.Print "Subject: " & subjectLine
' Debug.Print "Body:" & vbNewLine; bodyline
End With
goToNext:
Next I
Set C = Nothing
End Sub
Function SendMailFunction(emAddress As String, subjectLine As String, bodyline As String)
Dim OutApp As Object
Dim OutMail As Object
Dim cell As Range
Dim tb As ListObject
Dim NL As String
Dim DNL As String
Dim I As Integer
NL = vbNewLine
DNL = vbNewLine & vbNewLine
Application.ScreenUpdating = False
Set OutApp = CreateObject("Outlook.Application")
Set tb = ActiveSheet.ListObjects("Table10")
For I = 1 To ActiveSheet.ListObjects("Table10").ListRows.Count
Set OutMail = OutApp.CreateItem(0)
On Error Resume Next
With OutMail
.To = emAddress
.Subject = subjectLine
.Body = "Hello, We require an update as to the following:" & DNL & bodyline _
& DNL & _
"Please Send an update as to the status of these line items " & _
"providing the following: Packing Slips, Tracking Numbers and Updated Ship Dates."
.Display
End With
On Error GoTo 0
Set OutMail = Nothing
Next I
End Function

The following code uses the email script as a function, which is called from the top macro. Please click on answer if this solves your problem
Sub findMethodINtable()
Dim subjectLine As String
Dim bodyline As String
Dim tb As ListObject
Dim lineCounter As Long
Dim myArray1, arrayCounter As Long, tempNumb As Long
Dim nameCounter As Long
Dim emAddress As String
ReDim myArray1(1 To 1)
arrayCounter = 0
nameCounter = 1
Set tb = ActiveSheet.ListObjects("Table14")
For i = 1 To ActiveSheet.ListObjects("Table14").ListRows.Count
emAddress = tb.DataBodyRange.Cells(i, tb.ListColumns("Email Address").Index)
For x = LBound(myArray1) To UBound(myArray1)
On Error Resume Next
If emAddress = myArray1(x) Then GoTo goToNext
Next x
On Error GoTo 0
subjectLine = "Order(s) # "
ReDim Preserve myArray1(1 To nameCounter)
myArray1(nameCounter) = emAddress
nameCounter = nameCounter + 1
lineCounter = 1
With tb.ListColumns("Email Address").Range
Set c = .Find(emAddress, LookIn:=xlValues)
If Not c Is Nothing Then
firstAddress = c.Address
Beep
arrayCounter = arrayCounter + 1
Do
nRow = c.Row - 1
If lineCounter = 1 Then
subjectLine = subjectLine & tb.DataBodyRange.Cells(nRow, tb.ListColumns("Order Number").Index)
lineCounter = lineCounter + 1
bodyline = "Order " & tb.DataBodyRange.Cells(nRow, tb.ListColumns("Order Number").Index) & ", Line Number " & tb.DataBodyRange.Cells(nRow, tb.ListColumns("Line Number").Index)
Else:
subjectLine = subjectLine & ", " & tb.DataBodyRange.Cells(nRow, tb.ListColumns("Order Number").Index)
bodyline = bodyline & vbNewLine & "Order " & tb.DataBodyRange.Cells(nRow, tb.ListColumns("Order Number").Index) & ", Line Number " & tb.DataBodyRange.Cells(nRow, tb.ListColumns("Line Number").Index)
End If
Set c = .FindNext(c)
Loop While Not c Is Nothing And c.Address <> firstAddress
End If
Run SendMailFunction(emAddress, subjectLine, bodyline)
' Debug.Print vbNewLine
' Debug.Print emAddress
' Debug.Print "Subject: " & subjectLine
' Debug.Print "Body:" & vbNewLine; bodyline
End With
goToNext:
Next i
Set c = Nothing
End Sub
Function SendMailFunction(emAddress As String, subjectLine As String, bodyline As String)
Dim OutApp As Object
Dim OutMail As Object
Dim cell As Range
Dim tb As ListObject
Dim NL As String
Dim DNL As String
NL = vbNewLine
DNL = vbNewLine & vbNewLine
Application.ScreenUpdating = False
Set OutApp = CreateObject("Outlook.Application")
Set tb = ActiveSheet.ListObjects("Table14")
Set OutMail = OutApp.CreateItem(0)
On Error Resume Next
With OutMail
.To = emAddress
.Subject = subjectLine
.Body = "Hello, We require an update as to the following:" & DNL & bodyline _
& DNL & _
"Please Send an update as to the status of these line items " & _
"providing the following: Packing Slips, Tracking Numbers and Updated Ship Dates."
.Send
End With
On Error GoTo 0
Set OutMail = Nothing
End Function

This works for me, given table name is "Table14"
Sub wserlkug()
Dim OutApp As Object
Dim OutMail As Object
Dim cell As Range
Dim tb As ListObject
Dim NL As String
Dim DNL As String
NL = vbNewLine
DNL = vbNewLine & vbNewLine
Application.ScreenUpdating = False
Set OutApp = CreateObject("Outlook.Application")
Set tb = ActiveSheet.ListObjects("Table14")
For i = 1 To ActiveSheet.ListObjects("Table14").ListRows.Count
Set OutMail = OutApp.CreateItem(0)
On Error Resume Next
With OutMail
.To = ActiveSheet.ListObjects("Table14").DataBodyRange.Cells(i, tb.ListColumns("Email Address").Index)
.Subject = "Order # " & ActiveSheet.ListObjects("Table14").DataBodyRange.Cells(i, tb.ListColumns("Order Number").Index)
.Body = "Hello, We require an update as to the following:" & DNL & "Line #: " & ActiveSheet.ListObjects("Table14").DataBodyRange.Cells(i, tb.ListColumns("Line Number").Index) _
& DNL & _
"Please Send an update as to the status of these line items " & _
"providing the following: Packing Slips, Tracking Numbers and Updated Ship Dates."
.Send
End With
On Error GoTo 0
Set OutMail = Nothing
Next i
End Sub
You can actually use the object variable "tb" instead of ActiveSheet.ListObjects("Table14").... I placed that there to show how to reference row and column in a table.

Related

VBA - Repeat email function through multiple columns

So I built a code that works for mailing 1 list (in Column A): Cell A1 has a region, Cells A2 though last row have an email address that needs that email. This code works fine for column A. But if a made a list in Columns B-#( however many number of columns), could i add onto this code and make it create as many emails as there are columns, and send them to the list of people below row 2.
In other words, can we make this say for Each column with a value in the first row create and email and send it to everyone else below it?
thanks
Sub emailfromcolumns()
Dim olApp As Outlook.Application
Dim olMail As Outlook.MailItem
Dim MailMessage As String
Dim i As Long
Dim LastRow As Long
Dim Namelist As String
LastRow = Range("A" & rows.Count).End(xlUp).Row
'email recipients are in row 2 to the last row
For i = 2 To LastRow
If Sheets("Recipients").Range("A2").Value <> "" Then
Namelist = Namelist & ";" & Sheets("Recipients").Range("A" & i).Value
End If
Next
MailMessage = "<HTML><BODY> Good Afternoon All, <br><br>" _
& "<li>Please let me know if there is anything else you need or any changes you would like to see.<br><br>" _
& "<li>Thanks,<br><br>" _
& "Thank you, Pricing Team<br><br>" _
Set olApp = GetObject(Class:="Outlook.Application")
If olApp Is Nothing Then
Set olApp = CreateObject(Class:="outlook.application")
End If
Set olMail = olApp.CreateItem(0)
With olMail
.To = Namelist
.Subject = Range("A1").Value & " 60 Day Expiration " & Format(MonthName(Month(Now)))
.display
.HTMLBody = MailMessage
.Attachments.Add ("C:\Desktop\60 Day Exp\Savefiles\" & Range("A1").Value & " 60 Day Expirations " & Format(MonthName(Month(Now))) & ".xlsx")
.Save
.Close 1
End With
Set olMail = Nothing
Set olApp = Nothing
Application.ScreenUpdating = True
End Sub
I would make your existing routine accept a column number so you can pass any column to it, and then it will work for that column e.g.
Sub emailfromcolumns(COL As Long)
So then you can just call emailfromcolumns(1) to email for column A, emailfromcolumns(2) to email for column B etc.
Then you can create a second sub routine that finds out how many columns there are and just loops through them all, calling your existing routine:
Sub loopit()
Dim lastColumn As Long
Dim x As Long
lastColumn = Sheets("Recipients").Cells(1, Sheets("Recipients").Columns.Count).End(xlToLeft).Column
For x = 1 To lastColumn
emailfromcolumns (x)
Next x
End Sub
This means all you have to do to your existing code is replace any reference to column "A" with the variable COL - there are four lines:
change
LastRow = Range("A" & rows.Count).End(xlUp).Row
to
LastRow = Cells(Rows.Count, COL).End(xlUp).Row
change
If Sheets("Recipients").Range("A2").Value <> "" Then
Namelist = Namelist & ";" & Sheets("Recipients").Range("A" & i).Value
End If
to
If Cells(2, COL).Value2 <> "" Then
Namelist = Namelist & ";" & Cells(i, COL).Value2
End If
and the last two lines are within the e-mail bit:
.Subject = Sheets("Recipients").Cells(i, COL).Value2 & " 60 Day Expiration " & Format(MonthName(Month(Now)))
.Attachments.Add ("C:\Desktop\60 Day Exp\Savefiles\" & Sheets("Recipients").Cells(i, COL).Value2 & " 60 Day Expirations " & Format(MonthName(Month(Now))) & ".xlsx")
On top of this, your code has some risky sections where you're just referring to Range without declaring which sheet the range is on... below is full version tidied up with comments on the differences:
Sub emailfromcolumns(COL As Long)
Dim olApp As Outlook.Application
Dim olMail As Outlook.MailItem
Dim MailMessage As String
Dim i As Long
Dim LastRow As Long
Dim Namelist As String
Dim WS As Worksheet ' Declare a worksheet object
Set WS = ThisWorkbook.Worksheets("Recipients") ' set the worksheet object WS to "Recipients" for easy reference
LastRow = WS.Cells(WS.Rows.Count, COL).End(xlUp).Row ' last row now definitely referencing "Recipients" thanks to WS
'email recipients are in row 2 to the last row
' changed your "A2" check to outside the loop, don't need to check it each time
If WS.Cells(2, COL).Value2 <> "" Then
For i = 2 To LastRow
Namelist = Namelist & ";" & WS.Cells(i, COL).Value2
Next i
End If
MailMessage = "<HTML><BODY> Good Afternoon All, <br><br>" _
& "<li>Please let me know if there is anything else you need or any changes you would like to see.<br><br>" _
& "<li>Thanks,<br><br>" _
& "Thank you, Pricing Team<br><br>" _
Set olApp = GetObject(Class:="Outlook.Application")
If olApp Is Nothing Then Set olApp = CreateObject(Class:="outlook.application")
Set olMail = olApp.CreateItem(0)
With olMail
.To = Namelist
.Subject = WS.Cells(1, COL).Value2 & " 60 Day Expiration " & Format(MonthName(Month(Now)))
.display
.HTMLBody = MailMessage
.Attachments.Add ("C:\Desktop\60 Day Exp\Savefiles\" & WS.Cells(1, COL).Value2 & " 60 Day Expirations " & Format(MonthName(Month(Now))) & ".xlsx")
.Save
.Close 1
End With
Set olMail = Nothing
Set olApp = Nothing
Application.ScreenUpdating = True ' You didn't have anywhere that says Application.ScreenUpdating = False ?
End Sub
Sub emailfromcolumns()
Dim olApp As Outlook.Application
Dim olMail As Outlook.MailItem
Dim MailMessage As String
Dim i As Long
Dim z As Long
Dim LastRow As Long
Dim Namelist As String
Dim colCount As Long
'How Many Columns?
colCount = 4
'Loop through columns
For z = 1 To colCount
'email recipients are in row 2 to the last row
Namelist = vbNullString
With Worksheets("Recipients")
LastRow = .Cells(.Rows.Count, z).End(xlUp).Row
For i = 2 To LastRow
If .Cells(i, z).Value <> "" Then
Namelist = Namelist & ";" & .Cells(i, z).Value
End If
Next
End With
'Only create message if emails exist?
If Len(Namelist) > 0 Then
MailMessage = "<HTML><BODY> Good Afternoon All, <br><br>" _
& "<li>Please let me know if there is anything else you need or any changes you would like to see.<br> " _
& "<br>" _
& "<li>Thanks,<br><br>" _
& "Thank you, Pricing Team<br><br>" _
Set olApp = GetObject(Class:="Outlook.Application")
If olApp Is Nothing Then
Set olApp = CreateObject(Class:="outlook.application")
End If
Set olMail = olApp.CreateItem(0)
With olMail
.To = Namelist
.Subject = Sheets("Recipients").Cells(1, z).Value & " 60 Day Expiration " & Format(MonthName(Month(Now)))
.display
.HTMLBody = MailMessage
.Attachments.Add ("C:\Desktop\60 Day Exp\Savefiles\" & Sheets("Recipients").Cells(1, z).Value & " 60 Day Expirations " & Format(MonthName(Month(Now))) & ".xlsx")
.Save
.Close 1
End With
Set olMail = Nothing
Set olApp = Nothing
End If
Next z
Application.ScreenUpdating = True
End Sub

Email Reminder doesnt triggered (to send) even Value Change from Formula in Excel

I'm new to VB in Excel.
I made an email reminder program in Excel with value changed from formula (calculation) in one of the cell.
The problem is the email reminder did not pop up even though the conditions are met.
But when I put manually the number (to meet the condition), the email reminder did pop up.
Please help to make the program run if the cell value from calculation met the condition of the program. Thanks!
Here is the code:
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
Dim completed As Boolean
Dim rowCount As Long
Dim i As Integer
Dim Objek As String
Dim SatKer As String
Dim Hari As String
Dim AlamatEmail As String
Dim xMailBody As String
rowCount = 2
If Target.Cells.Count > 1 Then Exit Sub
For i = 1 To 5
rowCount = rowCount + 1
Set xRg = Range("O" & CStr(rowCount))
Objek = ActiveSheet.Range("F" & CStr(rowCount)).Value
SatKer = ActiveSheet.Range("G" & CStr(rowCount)).Value
Hari = ActiveSheet.Range("O" & CStr(rowCount)).Value
AlamatEmail = ActiveSheet.Range("S" & CStr(rowCount)).Value
If xRg = Target And Target.Value < 4 Then
Call Mail_small_Text_Outlook(Objek, SatKer, Hari, AlamatEmail)
End If
Next i
End Sub
Sub Mail_small_Text_Outlook(Objek As String, SatKer As String, Hari As String, AlamatEmail As String)
Dim xOutApp As Object
Dim xOutMail As Object
Dim xMailBody As String
Set xOutApp = CreateObject("Outlook.Application")
Set xOutMail = xOutApp.CreateItem(0)
xMailBody = "Yth. Bapak Widi " & vbNewLine & vbNewLine & _
"Laporan Penilaian " & Objek & " milik " & SatKer & " mendekati batas akhir pengumpulan." & vbNewLine & _
"Laporan tersebut harus disubmit dalam " & Hari & " hari." & vbNewLine & vbNewLine & _
"Mohon cek status laporan penilaian untuk keterangan laporan lebih detail."
On Error Resume Next
With xOutMail
.To = AlamatEmail
.cc = ""
.BCC = ""
.Subject = "Laporan Penilaian " & Objek & " milik " & SatKer
.HTMLBody = xMailBody
.Display 'or use .Send
End With
On Error GoTo 0
Set xOutMail = Nothing
Set xOutApp = Nothing
End Sub
The following should do what you expect, the code will loop through column O and if the value calculated is less than 4 then it will .Display the email:
Private Sub Worksheet_Calculate()
Dim ws As Worksheet: Set ws = Sheets("Sheet1")
'declare and set your worksheet, amend as required
LastRow = ws.Cells(ws.Rows.Count, "O").End(xlUp).Row
'get the last row with data on Column O
Dim completed As Boolean
Dim rowCount As Long
Dim i As Integer
Dim Objek As String
Dim SatKer As String
Dim Hari As String
Dim AlamatEmail As String
Dim xMailBody As String
For i = 3 To LastRow 'loop from row 3 to last on Column O
Set xRg = Range("O" & i)
Objek = ws.Range("F" & i).Value
SatKer = ws.Range("G" & i).Value
Hari = ws.Range("O" & i).Value
AlamatEmail = ws.Range("S" & i).Value
If ws.Cells(i, "O").Value < 4 Then 'if value is less than 4 then send email
Call Mail_small_Text_Outlook(Objek, SatKer, Hari, AlamatEmail)
End If
Next i
End Sub
Sub Mail_small_Text_Outlook(Objek As String, SatKer As String, Hari As String, AlamatEmail As String)
Dim xOutApp As Object
Dim xOutMail As Object
Dim xMailBody As String
Set xOutApp = CreateObject("Outlook.Application")
Set xOutMail = xOutApp.CreateItem(0)
xMailBody = "Yth. Bapak Widi " & vbNewLine & vbNewLine & _
"Laporan Penilaian " & Objek & " milik " & SatKer & " mendekati batas akhir pengumpulan." & vbNewLine & _
"Laporan tersebut harus disubmit dalam " & Hari & " hari." & vbNewLine & vbNewLine & _
"Mohon cek status laporan penilaian untuk keterangan laporan lebih detail."
On Error Resume Next
With xOutMail
.To = AlamatEmail
.cc = ""
.BCC = ""
.Subject = "Laporan Penilaian " & Objek & " milik " & SatKer
.HTMLBody = xMailBody
.Display 'or use .Send
End With
On Error GoTo 0
Set xOutMail = Nothing
Set xOutApp = Nothing
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

VBA - Creating Word Document from Excel and Edit Certain Line to Contain Bold Text

I am looking to bold every second line entry on a word document that receives input from an excel spreadsheet. In other words, I want the resulting word document to have each line containing 'ID:' to contain bold text. I've looked into other examples but I keep getting errors such as mismatch.
Sub ExceltoWord_TestEnvironment()
Dim wApp As Object
Dim wDoc As Object
Dim strSearchTerm
Dim FirstMatch As Range
Dim FirstAddress
Dim intMyVal As String
Dim lngLastRow As Long
Dim strRowNoList As String
Dim intPlaceHolder As Integer
Set wApp = CreateObject("Word.Application")
Set wDoc = CreateObject("Word.Document")
wApp.Visible = True
Set wDoc = wApp.Documents.Add
wDoc.Range.ParagraphFormat.SpaceBefore = 0
wDoc.Range.ParagraphFormat.SpaceAfter = 0
strSearchTerm = InputBox("Please enter the date to find", "Search criteria")
If strSearchTerm <> "" Then
Set FirstMatch = ActiveSheet.Cells.Find(strSearchTerm, LookAt:=xlPart, MatchCase:=False)
If FirstMatch Is Nothing Then
MsgBox "That date could not be found"
Else
FirstAddress = FirstMatch.Address
intMyVal = strSearchTerm
lngLastRow = Cells(Rows.Count, "F").End(xlUp).Row 'Search Column F, change as required.
For Each cell In Range("F1:F" & lngLastRow) 'F is column
If InStr(1, cell.Value, intMyVal) Then
If strRowNoList = "" Then
strRowNoList = strRowNoList & cell.Row
intPlaceHolder = cell.Row
wDoc.Content.InsertAfter "Group: " & Cells(intPlaceHolder, 3) & vbNewLine
wDoc.Content.InsertAfter "ID: " & Cells(intPlaceHolder, 2) & vbNewLine
wDoc.Content.InsertAfter "Name: " & vbNewLine & vbNewLine
Else
strRowNoList = strRowNoList & ", " & cell.Row
intPlaceHolder = cell.Row
wDoc.Content.InsertAfter "Group: " & Cells(intPlaceHolder, 3) & vbNewLine
wDoc.Content.InsertAfter "ID: " & Cells(intPlaceHolder, 2) & vbNewLine
wDoc.Content.InsertAfter "Name: " & vbNewLine & vbNewLine
End If
Next cell
MsgBox strRowNoList
While Not FirstMatch Is Nothing
Set FirstMatch = ActiveSheet.Cells.FindNext(FirstMatch)
If FirstMatch.Address = FirstAddress Then
Set FirstMatch = Nothing
End If
Wend
End If
End If
End Sub
Example:
Group: Group A
ID: 123456
Name: Jon Snow
Group: Group B
ID: 789101
Name: Samwell Tarly
I was able to find a work around. Thought I would post it here to help others. Sorry my code isn't as clean as I would like it to be. Copying and pasting didn't quite match up.
Sub ExceltoWord_TestEnvironment()
Dim wApp As Object
Dim wDoc As Object
Dim strSearchTerm
Dim FirstMatch As Range
Dim FirstAddress
Dim intMyVal As String
Dim lngLastRow As Long
Dim strRowNoList As String
Dim intPlaceHolder As Integer
Set wApp = CreateObject("Word.Application")
Set wDoc = CreateObject("Word.Document")
wApp.Visible = True
Set wDoc = wApp.Documents.Add
wDoc.Range.ParagraphFormat.SpaceBefore = 0
wDoc.Range.ParagraphFormat.SpaceAfter = 0
strSearchTerm = InputBox("Please enter the date to find", "Search criteria")
If strSearchTerm <> "" Then
Set FirstMatch = ActiveSheet.Cells.Find(strSearchTerm, LookAt:=xlPart, MatchCase:=False)
If FirstMatch Is Nothing Then
MsgBox "That date could not be found"
Else
FirstAddress = FirstMatch.Address
intMyVal = strSearchTerm
lngLastRow = Cells(Rows.Count, "F").End(xlUp).Row 'Search Column F, change as required.
For Each cell In Range("F1:F" & lngLastRow) 'F is column
If InStr(1, cell.Value, intMyVal) Then
If strRowNoList = "" Then
strRowNoList = strRowNoList & cell.Row
intPlaceHolder = cell.Row
intParaCount = wDoc.Paragraphs.Count
i = 2
Set objParagraph = wDoc.Paragraphs(i).Range
With objParagraph
.Font.Bold = True
End With
wDoc.Content.InsertAfter "Group: " & Cells(intPlaceHolder, 3) & vbNewLine
wDoc.Content.InsertAfter "ID: " & Cells(intPlaceHolder, 2) & vbNewLine
wDoc.Content.InsertAfter "Name: " & vbNewLine & vbNewLine
i = i + 4 'paragraph number
Else
strRowNoList = strRowNoList & ", " & cell.Row
intPlaceHolder = cell.Row
wDoc.Content.InsertAfter "Group: " & Cells(intPlaceHolder, 3) & vbNewLine
wDoc.Content.InsertAfter "ID: " & Cells(intPlaceHolder, 2) & vbNewLine
wDoc.Content.InsertAfter "Name: " & vbNewLine & vbNewLine
i = i + 4
End If
Next cell
MsgBox strRowNoList
While Not FirstMatch Is Nothing
Set FirstMatch = ActiveSheet.Cells.FindNext(FirstMatch)
If FirstMatch.Address = FirstAddress Then
Set FirstMatch = Nothing
End If
Wend
End If
End If
End Sub
The code utilizes .paragraphs() where 'i' is the paragraph you want to bold:
i = 2
Set objParagraph = wDoc.Paragraphs(i).Range
With objParagraph
.Font.Bold = True
End With
And the difference in paragraphs is added after each iteration
i = i + 4 'paragraph number

Stop macro if column is blank excel vba

I have made some code but if the range R2:34 is blank, it will still open the template email with no data in him. Please tell me where am I doing the bad connection.
Sub 1()
Dim OutApp As Object
Dim OutMail As Object
Dim sTo As String
Dim spo As String
Dim emailRng As Range, cl As Range, dtrecuta As Range
Dim c As Range
For Each cell In Cells.Range("N2:N34")
If LCase(Cells(cell.Row, "N").Value) = "0" Or LCase(Cells(cell.Row, "N").Value) < "480" Then
On Error Resume Next
Cells(cell.Row, "R").Value = Cells(cell.Row, "M").Value
Else
Cells(cell.Row, "R").Value = Null
End If
Next cell
a = CLng(Date)
Set emailRng = Worksheets("Sheet1").Range("r2:r34")
Set dtrecuta = Worksheets("Sheet1").Range("P2")
For Each cl In emailRng
sTo = sTo & ";" & cl.Value
Next
sTo = Mid(sTo, 2)
Set OutApp = CreateObject("Outlook.Application")
Set OutMail = OutApp.CreateItemFromTemplate("C:\Users\Marius\AppData\Roaming\Microsoft\Templates\statistica.oft")
On Error Resume Next
With OutMail
.To = sTo
.CC = ""
.BCC = ""
.Subject = "TESTARE Statistica pentru data de " & dtrecuta
strbody = "Buna " & " , " & vbNewLine & vbNewLine & _
"Te rog sa trimiti statistica astazi " & a & " pana in ora 10:00, " & _
" pentru data de " & dtrecuta & vbNewLine & vbNewLine & "O zi buna." & _
" " & vbNewLine & vbNewLine & " Acesta este un mesaj automat nu raspundeti la acest e-mail. "
.Display
.Body = strbody & Signature
.send
End With
On Error GoTo cleanup
Set OutMail = Nothing
cleanup:
Set OutMail = Nothing
Set OutApp = Nothing
Application.ScreenUpdating = True
End Sub
Add an IF statement just after setting your range to check if it is all blank cells:
Set emailRng = Worksheets("Sheet1").Range("r2:r34")
If WorksheetFunction.CountBlank(emailRng) = emailRng.Cells.Count Then Exit Sub 'No data