The code successfully sends the first email, but I am encountering an error on the second.
[Run-time error '-2147221238 (8004010a)': The item has been moved or deleted].
My goal is to use the button to automatically send reminder emails based on the criteria from the IF statements. The debug references the .To = Recipient line.
Private Sub CommandButton1_Click()
Dim objOutlook As Object
Dim objEmail As Object
Dim Row As Integer
Dim Recipient As String
Dim Requestor As String
Dim CQID As String
Dim lastRow As Long
Set objOutlook = CreateObject("Outlook.Application")
Set objEmail = objOutlook.CreateItem(olMailItem)
lastRow = Cells(Rows.Count, 1).End(xlUp).Row
With objEmail
For Row = 2 To lastRow
If Cells(Row, 12).Value = "10" And IsEmpty(Cells(Row, 13).Value) = True Then 'Prepares and sends email after 10 days and no reminder has already been sent. The second constraint is to prevent multiple emails from being sent if the button is pressed multiple times in the day.
Recipient = Cells(Row, 14).Value
Requestor = Cells(Row, 15).Value
CQID = Cells(Row, 1).Value
.To = Recipient '<---Debug reference
.CC = Requestor
.Subject = "Update Requested for " & CQID
.Body = "Please send us an update on " & CQID
'.Display
.Send
Cells(Row, 13).Value = "1st Reminder Sent" 'Prepares constraint for second reminder
End If
If Cells(Row, 12).Value = "15" And Cells(Row, 13).Value = "1st Reminder Sent" Then
Recipient = Cells(Row, 14).Value
Requestor = Cells(Row, 15).Value
.To = Recipient
.CC = Requestor
.Subject = "Update Requested for " & CQID
.Body = "Please send us an update on " & CQID
'.Display
.Send
Cells(Row, 13).Value = "2nd Reminder Sent"
End If
Next Row
End With
Set objEmail = Nothing
Set objOutlook = Nothing
End Sub
Any help with the direct issue or suggestions for general improvements are greatly appreciated.
No need for second set objEmail to Creates a new Outlook item, simply move it inside your loop
Dim Row As Long
For Row = 2 To lastRow
Dim objEmail As Object
Set objEmail = objOutlook.CreateItem(0)
Also its very impotent to specify the workbook or worksheet in the code when referencing Cells(Row
Example
Option Explicit
Private Sub CommandButton1_Click()
Dim objOutlook As Object
Set objOutlook = CreateObject("Outlook.Application")
Dim Sht As Worksheet
Set Sht = ThisWorkbook.Worksheets("Sheet1")
With Sht
Dim lastRow As Long
lastRow = .Cells(Rows.Count, 1).End(xlUp).Row
Dim Row As Long
For Row = 2 To lastRow
Dim objEmail As Object
Set objEmail = objOutlook.CreateItem(0)
If Sht.Cells(Row, 12).Value = "10" And _
IsEmpty(Sht.Cells(Row, 13).Value) = True Then
Dim Recipient As String
Dim Requestor As String
Dim CQID As String
With objEmail
Recipient = Sht.Cells(Row, 14).Value
Requestor = Sht.Cells(Row, 15).Value
CQID = Sht.Cells(Row, 1).Value
.To = Recipient
.CC = Requestor
.Subject = "Update Requested for "
.Body = "Please send us an update on "
.Display
' .Send
Sht.Cells(Row, 13).Value = "1st Reminder Sent"
End With '<-email
Else
If Sht.Cells(Row, 12).Value = "15" And _
Sht.Cells(Row, 13).Value = "1st Reminder Sent" Then
With objEmail
Recipient = Sht.Cells(Row, 14).Value
Requestor = Sht.Cells(Row, 15).Value
.To = Recipient
.CC = Requestor
.Subject = "Update Requested for " & CQID
.Body = "Please send us an update on " & CQID
.Display
' .Send
Sht.Cells(Row, 13).Value = "2nd Reminder Sent"
End With '<-email
End If
End If
Next Row
End With '<-sht
Set objEmail = Nothing
Set objOutlook = Nothing
End Sub
See fully qualified examples
Related
can anyone explain to me the proper way to loop a certain range? I do not understand this part on how to make this work please? How do I do this only from row 2 to 4? It has a compile error, loop without for, any idea how to amend this please
Sub send_mass_email_display_only()
Dim i As Integer
Dim name As String, email As String, body As String, subject As String, copy As String, pdfadd As String
Dim OutApp As Object
Dim OutMail As Object
body = ActiveSheet.TextBoxes("TextBox 1").Text
For i = 2 To 4
'Loop down name column starting at row 2 column 1
Do While Cells(i, 1).Value <> ""
name = Split(Cells(i, 1).Value, " ")(0)
'name = Cells(i, 1).Value
email = Cells(i, 2).Value
subject = Cells(i, 3).Value
copy = Cells(i, 4).Value
pdfadd = Cells(i, 5).Value
body = Replace(body, "C1", name)
Set OutApp = CreateObject("Outlook.Application")
Set OutMail = OutApp.CreateItem(0)
With OutMail
.To = email
.cc = copy
.subject = subject
.body = body
.Attachments.Add (pdfadd)
.display
'.Send
End With
body = ActiveSheet.TextBoxes("TextBox 1").Text 'reset body text
Next i
Set OutMail = Nothing
Set OutApp = Nothing
'MsgBox "Email(s) Sent!"
End Sub
I tried as FaneDuru/grayProgrammerz suggested to delete the Do While line... seems that this works so far
Option Explicit
Sub send_mass_email_display_only()
Dim i As Integer
Dim name As String, email As String, body As String, subject As String, copy As String, pdfadd As String
Dim OutApp As Object
Dim OutMail As Object
body = ActiveSheet.TextBoxes("TextBox 1").Text
For i = 2 To 4
'Specific rows
name = Split(Cells(i, 1).Value, " ")(0)
'name = Cells(i, 1).Value
email = Cells(i, 2).Value
subject = Cells(i, 3).Value
copy = Cells(i, 4).Value
pdfadd = Cells(i, 5).Value
body = Replace(body, "C1", name)
Set OutApp = CreateObject("Outlook.Application")
Set OutMail = OutApp.CreateItem(0)
With OutMail
.To = email
.cc = copy
.subject = subject
.body = body
.Attachments.Add (pdfadd)
.display
'.Send
End With
body = ActiveSheet.TextBoxes("TextBox 1").Text 'reset body text
Next i
Set OutMail = Nothing
Set OutApp = Nothing
'MsgBox "Email(s) Sent!"
End Sub
I have three columns: A) Enterprises B) Email address matching the enterprise C) Yes or No
If there is a YES in column C, I want to send a message to the email address in column B.
This is what I have. Nothing is happening.
Sub Test2()
Dim OutApp As Outlook.Application
Dim OutMail As Outlook.MailItem
Dim cell As Range
Application.ScreenUpdating = False
Set OutApp = CreateObject("Outlook.Application")
On Error GoTo cleanup
For Each cell In Columns("B").Cells.SpecialCells(xlCellTypeConstants)
If cell.Value Like "?*#?*.?*" And _
LCase(Cells(cell.Row, "C").Value) = "yes" _
And LCase(Cells(cell.Row, "D").Value) <> "send" Then
Set OutMail = OutApp.CreateItem(olMailItem)
On Error Resume Next
With OutMail
.To = cell.Value
.Subject = "Reminder"
.Body = "Dear " & Cells(cell.Row, "A").Value _
& vbNewLine & vbNewLine & _
"Please contact us to discuss bringing " & _
"your account up to date."
Attachments.Add ("\\C:\test.pdf")
.Send '
End With
On Error GoTo 0
Cells(cell.Row, "D").Value = "send"
Set OutMail = Nothing
End If
Next cell
cleanup:
Set OutApp = Nothing
Application.ScreenUpdating = True
End Sub
The code below will loop through Row 2 to the last row in the UsedRange and make sure that Columns A, B & C are not empty as well as check to make sure Column D is empty, which the code uses as a flag to show whether the email has previously been sent.
I've added a Regex validation function to the code to validate the email address.
Sub LoopThroughRange_SendEmail()
Dim OutApp As Object: Set OutApp = CreateObject("Outlook.Application")
Dim OutMail As Object: Set OutMail = OutApp.CreateItem(0)
Dim oRegEx As Object
Set oRegEx = CreateObject("VBScript.RegExp")
Dim i As Long
Dim ws As Worksheet: Set ws = ThisWorkbook.Worksheets("Sheet1")
'declare and set the worksheet you are working with
For i = 2 To ws.UsedRange.Rows.Count
'loop from Row 2 To Last Row in UsedRange
If ws.Cells(i, "A").Value <> "" And ws.Cells(i, "B").Value <> "" And ws.Cells(i, "C").Value = "Yes" And ws.Cells(i, "D").Value = "" Then
' make sure that Columns A, B & C are not empty and D is empty (which we will use as a flag to show that the email did get sent.
If ValidEmail(ws.Cells(i, "B").Value, oRegEx) Then
With OutMail
.To = ws.Cells(i, "B").Value
.CC = ""
.BCC = ""
.Subject = "Reminder"
.Body = "Dear " & Cells(cell.Row, "A").Value _
& vbNewLine & vbNewLine & _
"Please contact us to discuss bringing " & _
"your account up to date."
.Attachments.Add ("\\C:\test.pdf")
.Display '.Send
End With
ws.Cells(i, "D").Value = "Sent # " & Format(Now(), "yyyy-MM-dd hh:mm:ss")
Else
ws.Cells(i, "D").Value = "Email not valid"
End If
End If
End Sub
Public Function ValidEmail(pAddress As String, ByRef oRegEx As Object) As Boolean
With oRegEx
.Pattern = "^(([a-zA-Z0-9_\-\.\']+)#((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)(\s*;\s*|\s*$))+$" 'pattern for multiple email addresses included
ValidEmail = .test(pAddress)
End With
End Function
I am trying to send an email with the below code from my workbook. It works fine but only until I try to attach a file.
The file is created by another VBA code and the file name is defined by the cell values specified below, but I get a debug error when I try to run the code and it won't attach. I've tested with a named path eg C:test\test.docx and it works fine.
How can I get it to accept the path based on the cell values? I've set it to .Display whilst testing rather than send.
Option Explicit
Option Compare Text 'ignore case sensitivity when comparing strings
Sub SendEmail()
Dim objOutlook As Object
Dim objMail As Object
Dim OL As Outlook.Application, ES As Worksheet, r As Long, i As Long
Set objOutlook = CreateObject("Outlook.Application")
Set objMail = objOutlook.CreateItem(0)
Dim path As String
path = "\\Wbcphfil01.wbc.lan\dts\Groups\Operational_Services\opserv_group\Enforcement\NRSWA\Licences\Mobile Plant\Applications 2019-20\" & Cells(i, 4) & " (" & Cells(i, 13) & ").docx"
r = Cells(Rows.Count, 1).End(xlUp).Row
For i = 5 To r
With Cells(i, 7)
If .Value <> "" And Cells(i, 5) = "Mobile Plant" Then
With objMail
.To = Cells(i, 11).Value
.Subject = "Your " & Cells(i, 5).Value & " licence - " & Cells(i, 4).Value
.Body = "abc"
.Attachments.Add path
.Display
End With
End If
End With
Next i
Set objOutlook = Nothing
Set objMail = Nothing
End Sub
You are using Cells(i, 4) on the path to the file before you defined what the variable i actually is! Maybe move the path inside your For Loop?
Option Explicit
Option Compare Text 'ignore case sensitivity when comparing strings
Sub SendEmail()
Dim objOutlook As Object
Dim objMail As Object
Dim OL As Outlook.Application, ES As Worksheet, r As Long, i As Long
Set objOutlook = CreateObject("Outlook.Application")
Set objMail = objOutlook.CreateItem(0)
Dim path As String
r = Cells(Rows.Count, 1).End(xlUp).Row
For i = 5 To r
path = "\\Wbcphfil01.wbc.lan\dts\Groups\Operational_Services\opserv_group\Enforcement\NRSWA\Licences\Mobile Plant\Applications 2019-20\" & Cells(i, 4) & " (" & Cells(i, 13) & ").docx"
With Cells(i, 7)
If .Value <> "" And Cells(i, 5) = "Mobile Plant" Then
With objMail
.To = Cells(i, 11).Value
.Subject = "Your " & Cells(i, 5).Value & " licence - " & Cells(i, 4).Value
.Body = "abc"
.Attachments.Add path
.Display
End With
End If
End With
Next i
Set objOutlook = Nothing
Set objMail = Nothing
End Sub
Below is code I have written to automate sending meeting invites.
The code picks content from cells in sheet: Final_List.
I have highlighted where I'm getting an error when I try get the recipient address from Excel
Application -defined or object - defined error.
Dim outlookApp As Outlook.Application
Dim outlookmeet As AppointmentItem
Dim myRequiredAttendee As Recipient
Dim sh As Worksheet
Dim RowCount As Long
RowCount = 2
'row 1 has headers
With Worksheets("Final_List")
Do While IsEmpty(Cells(RowCount, 1).Value) = False
Set outlookApp = CreateObject("Outlook.Application")
Set outlookmeet = outlookApp.CreateItem(olAppointmentItem)
With outlookmeet
.MeetingStatus = olMeeting
.Subject = Cells(RowCount, 1).Value & " - " & Cells(RowCount, 2).Value
.Location = Cells(RowCount, 3).Value
.Start = Cells(RowCount, 5).Value
.Duration = Cells(RowCount, 7).Value
'getting errors on this line
.Recipients.Add (Cells(RowCount, 6).Value)
.Recipients.ResolveAll
.Body = Cells(RowCount, 4).Value
.Send
End With
RowCount = RowCount + 1
Loop
End With
Set outlookmeet = Nothing
Set outlookApp = Nothing
MsgBox "All invites sent!"
The AppointmentItem object doesn't have a Recipient property. Compare MSDN library
I got this solution:
Sub ScheduleMeeting()
Dim outlookApp As Outlook.Application
Dim outlookmeet As Outlook.AppointmentItem
Dim RowCount As Long
Dim Name1 As Variant
RowCount = 2
'row 1 has headers
Worksheets("MeetingInvite").Activate
With Worksheets("MeetingInvite")
Do While IsEmpty(Cells(RowCount, 1).Value) = False
Set outlookApp = CreateObject("Outlook.Application")
Set outlookmeet = outlookApp.CreateItem(olAppointmentItem)
With outlookmeet
.MeetingStatus = olMeeting
.Subject = Cells(RowCount, 1).Value
.Location = Cells(RowCount, 2).Value
.Start = Cells(RowCount, 4).Value
.Duration = Cells(RowCount, 6).Value
.RequiredAttendees = Cells(RowCount, 5).Value
.Body = Cells(RowCount, 3).Value
.Display
End With
RowCount = RowCount + 1
Loop
End With
Set outlookmeet = Nothing
Set outlookApp = Nothing
'MsgBox "All invites sent!"
End Sub
I'm working towards improving my efficiency at my workplace. For this there is a task of sending an e-mail to a list of people.
For this I have created the following code. Would like to know if this can be improved? This code takes the information from sheet "Final_list" in a workbook and headers are in row 1.
Sub EmailToAll()
Dim outlookApp As Outlook.Application
Dim outlookMail As Outlook.MailItem
Set outlookApp = CreateObject("Outlook.Application")
Set outlookMail = outlookApp.CreateItem(olMailItem)
Dim sh As Worksheet
Dim RowCount As Integer
Worksheets("Final_List").Activate
RowCount = 2
Set sh = ActiveSheet
Do While IsEmpty(sh.Cells(RowCount, 1).Value) = False
Set outlookApp = CreateObject("Outlook.Application")
Set outlookMail = outlookApp.CreateItem(olMailItem)
With outlookMail
'MsgBox sh.Cells(RowCount, 7).Value
.To = sh.Cells(RowCount, 7).Value
.CC = sh.Cells(RowCount, 9).Value
.BCC = Empty
.Subject = "[Update]" & " " & sh.Cells(RowCount, 1).Value & "-" & sh.Cells(RowCount, 8).Value
.BodyFormat = 2
.HTMLBody = "Hello "
'.Display
'.Save
'.Close
.Send
'MsgBox "Mail saved for" & sh.Cells(RowCount, 7).Value & "!"
RowCount = RowCount + 1
End With
Loop
Set outlookMail = Nothing
Set outlookApp = Nothing
MsgBox "All mails sent!"
End Sub
You do not need to create Outlook Object twice . Set outlookApp = CreateObject("Outlook.Application") and change Dim RowCount As Integer to Dim RowCount As Long
Also avoid .Activate
Option Explicit
Sub EmailToAll()
Dim outlookApp As Outlook.Application
Dim outlookMail As Outlook.MailItem
Dim RowCount As Long
Set outlookApp = CreateObject("Outlook.Application")
RowCount = 2
With Worksheets("Final_List")
Do While IsEmpty(Cells(RowCount, 1).Value) = False
Set outlookMail = outlookApp.CreateItem(olMailItem)
With outlookMail
.To = Cells(RowCount, 7).Value
.CC = Cells(RowCount, 9).Value
.BCC = Empty
.Subject = "[Update]" & " " & Cells(RowCount, 1).Value & "-" & Cells(RowCount, 8).Value
.BodyFormat = 2
.HTMLBody = "Hello "
.Send
End With
RowCount = RowCount + 1
Loop
End With
Set outlookMail = Nothing
Set outlookApp = Nothing
MsgBox "All mails sent!"
End Sub
Not sure exactly what parts of this you would like to optimise but after looking at your example, here are a couple of things which I would look at changing;
The only things which are changing within the loop are the recipients and the subject line, the body is always the same (obviously I don't know what is stored in those cells) but maybe you could just construct the recipients string within the loop which should work fine if you separate the email addresses with semi-colons and send one email instead of multiple emails?
The other thing which I would mention is that you are stopping when you encounter a blank line which means that the loop may not pick up all recipients if someone deleted that line by mistake. There are many much more robust ways of locating the end of the data you could use.
Hope that helps.