This should be straight-forward but I somehow can't get it right. I am trying to set-up an automatic email blast from Excel. I have followed step by step the instructions from other posts here, with no success. This is a dummy example I've created, for the sake of simplicity.
I would like to:
send emails to everybody in the list
conditionally replace certain keywords in the body
populate a column with the delivery status for each email (sent/failed)
My current code sends the email only to the first person in the list. I've used my personal email address for testing purposes. I wonder if sending the emails to the same address could be the issue. If anybody can provide some guidance, would be much appreciated!
Sub SendMail()
Dim EmailSent, EmailFailed, i As Integer
Dim StatusSent, StatusFailed As String
Dim olApp As Outlook.Application
Set olApp = CreateObject("Outlook.Application")
Dim olMail As Outlook.MailItem
Set olMail = olApp.CreateItem(olMailItem)
EmailSent = 0
EmailFailed = 0
StatusFailed = "failed"
StatusSent = "sent"
i = 1
Do
DoEvents
With olMail
.To = Cells(i, 1).Value
.Subject = "test"
.CC = ""
.BCC = ""
.Importance = olImportanceHigh
.BodyFormat = olFormatHTML
.HTMLBody = Cells(i, 2).Value
If Cells(i, 3) = 1 Then
.HTMLBody = VBA.Replace(olMail.HTMLBody, "replace_me", Cells(i, 4))
Else
.HTMLBody = VBA.Replace(olMail.HTMLBody, "replace_me", Cells(i, 5))
End If
.send
End With
On Error Resume Next
olMail.send
If Err Then
EmailFailed = EmailFailed + 1
ActiveSheet.Cells(i, 6).Value = StatusFailed 'change status from pending to failed
Else
EmailSent = EmailSent + 1
ActiveSheet.Cells(i, 6).Value = StatusSent 'change status from pending to sent
End If
i = i + 1
Loop Until i = Range(Range("A1"), Range("A1").End(xlDown)).Count
If EmailSent = 0 Then
MsgBox Prompt:="Emails could not be sent"
Else
MsgBox Prompt:="Sent emails: " & EmailSent & vbNewLine _
& "Failed emails: " & EmailFailed
End If
On Error GoTo 0
Set olApp = Nothing
Set olMail = Nothing
End Sub
You're missing two crucial lines in your Do loop:
Set olMail = olApp.CreateItem(olMailItem)
and at the end:
Set olMail = Nothing
Try this instead:
Sub SendMail()
Dim EmailSent, EmailFailed, i As Integer
Dim StatusSent, StatusFailed As String
Dim olApp As Outlook.Application
Set olApp = CreateObject("Outlook.Application")
Dim olMail As Outlook.MailItem
EmailSent = 0
EmailFailed = 0
StatusFailed = "failed"
StatusSent = "sent"
i = 1
Do
DoEvents
Set olMail = olApp.CreateItem(olMailItem)
With olMail
.To = Cells(i, 1).Value
.Subject = "test"
.CC = ""
.BCC = ""
.Importance = olImportanceHigh
.BodyFormat = olFormatHTML
.HTMLBody = Cells(i, 2).Value
If Cells(i, 3) = 1 Then
.HTMLBody = VBA.Replace(olMail.HTMLBody, "replace_me", Cells(i, 4))
Else
.HTMLBody = VBA.Replace(olMail.HTMLBody, "replace_me", Cells(i, 5))
End If
.send
End With
On Error Resume Next
olMail.send
If Err Then
EmailFailed = EmailFailed + 1
ActiveSheet.Cells(i, 6).Value = StatusFailed 'change status from pending to failed
Else
EmailSent = EmailSent + 1
ActiveSheet.Cells(i, 6).Value = StatusSent 'change status from pending to sent
End If
Set olMail = Nothing
i = i + 1
Loop Until i = Range(Range("A1"), Range("A1").End(xlDown)).Count
If EmailSent = 0 Then
MsgBox Prompt:="Emails could not be sent"
Else
MsgBox Prompt:="Sent emails: " & EmailSent & vbNewLine _
& "Failed emails: " & EmailFailed
End If
On Error GoTo 0
Set olApp = Nothing
End Sub
Related
Seems that i can't add the text while adding the signature in the same code. Below you may see it:
Set OutApp = CreateObject("Outlook.Application")
Set OutMail = OutApp.CreateItem(0)
With OutMail
.to = email
.cc = copy
.subject = subject
.body = body
.HTMLbody = sig
That HTMLbody is deleting the body that i have 1 row up in the formula.
I have tryed to modify as i saw in other examples here, but nothing seems to work.Bellow you can see also the whole project.
Can you check and let me know were i have faild?
Sub send_mass_email()
Dim i As Integer
Dim name, email, body, subject, copy, place, business As String
Dim OutApp As Object
Dim OutMail As Object
Dim fsFile As Object
Dim fso As Object
Dim fsFolder As Object
Dim strFolder As String
Dim sig As String
sig = ReadSignature("adi.htm")
HTMLbody = ActiveSheet.TextBoxes("TextBox 1").Text
i = 2
'Loop down name column starting at row 2 column 1
Do While Cells(i, 1).Value <> ""
name = Split(Cells(i, 1).Value, " ")(0) 'extract first name
email = Cells(i, 2).Value
subject = Cells(i, 3).Value
copy = Cells(i, 4).Value
business = Cells(i, 5).Value
answ = MsgBox("what it need to be attach " & Cells(i, 1) & " ?", vbYesNo + vbExclamation, "PSK Check")
If answ <> vbYes Then
Set OutApp = CreateObject("Outlook.Application")
Set OutMail = OutApp.CreateItem(0)
With OutMail
.to = email
.cc = copy
.subject = subject
.HTMLbody = body
.HTMLbody = sig
.display
End With
End If
If answ = vbYes Then
Set xFileDlg = Application.FileDialog(msoFileDialogFilePicker)
If xFileDlg.Show = -1 Then
'replace place holders
Set OutApp = CreateObject("Outlook.Application")
Set OutMail = OutApp.CreateItem(0)
With OutMail
.to = email
.cc = copy
.subject = subject
.HTMLbody = body & sig
.display
For Each xFileDlgItem In xFileDlg.SelectedItems
.Attachments.Add xFileDlgItem
Next xFileDlgItem
'.Send
End With
End If
'reset body text
body = ActiveSheet.TextBoxes("TextBox 1").Text
End If
i = i + 1
Loop
Set OutMail = Nothing
Set OutApp = Nothing
End Sub
Try replacing these two lines...
.HTMLbody = body
.HTMLbody = sig
with
.HTMLbody = body & sig
By the way, if you want a line break between the body and signature, try the following instead...
.HTMLbody = body & "<br>" & sig
I have code that works fine in all aspects, but I can not find a way to create a hyperlink in an Outlook appointment. The address is placed in column H in Excel, and I want to use VBA to export it to a certain calendar. Any help would greatly be appriciated.
My code is as follows:
Sub Appointments()
Const olAppointmentItem As Long = 1
Dim OLApp As Object
Dim OLNS As Object
Dim OLAppointment As Object
Dim miCalendario As Object
Dim r As Long
On Error Resume Next
Set OLApp = GetObject(, "Outlook.Application")
If OLApp Is Nothing Then Set OLApp = CreateObject("Outlook.Application")
On Error GoTo 0
If Not OLApp Is Nothing Then
Set OLNS = OLApp.GetNamespace("MAPI")
OLNS.Logon "Outlook"
b = 1
r = 2
Dim mysub, myStart, myEnd, mydes, myallday
While Len(Cells(r, 5).Text) <> 0
mysub = Cells(r, 7)
If Not Cells(r, 13).Value = 0 Then
mysub = mysub & "(s. " & Cells(r, 13).Value & ")" & vbCrLf
End If
'& ", " & Cells(r, 3)
myStart = DateValue(Cells(r, 1).Value) + Cells(r, 2).Value
myEnd = DateValue(Cells(r, 1).Value) + Cells(r, 3).Value
mydes = ""
Set miCalendario = OLApp.Session.GetDefaultFolder(9).Folders(ActiveSheet.Name)
Set OLAppointment = miCalendario.Items.Add(olAppointmentItem)
Dim olItems As Items
Dim olApptItem As Outlook.AppointmentItem
Set olItems = miCalendario.Items
Set olApptItem = miCalendario.Items.GetFirst
'add appointments
On Error Resume Next
With OLAppointment
.Subject = mysub
.Start = myStart
.End = myEnd
.Body = mydes
If Not Cells(r, 1).Value = 0 Then
If Not Cells(r, 8).Value = 0 Then
mydes = mydes & Cells(1, 8).Value & " - " & Cells(r, 8).Value & vbCrLf
End If
.Body = mydes
End If
.Location = Cells(r, 4).Value .Save
End With
r = r + 1
b = b + 1
Wend
Set OLAppointment = Nothing
Set OLNS = Nothing
Set OLApp = Nothing
End If
End Sub
You need to use .HTMLBody insted .Body
.HTMLbody = "link_Mask"
I hope it'll help
The following code works to send emails 7 days on or before the past due date but in order for it to run, it needs to be assigned to a button within Excel. When the file is opened, I want it to run the code automatically and send emails to those that have upcoming or overdue tasks. It needs to stop sending emails where tasks have been marked "Completed".
Sub eMail()
Dim lRow As Integer
Dim i As Integer
Dim toDate As Date
Dim toList As String
Dim eSubject As String
Dim eBody As String
With Application
.ScreenUpdating = False
.EnableEvents = False
.DisplayAlerts = False
End With
Sheets(1).Select
lRow = Cells(Rows.Count, 5).End(xlUp).Row
Set OutApp = CreateObject("Outlook.Application")
For i = 2 To lRow
If Cells(i, 5) <> "" Then
toDate = Replace(Cells(i, 5), ".", "/")
If Left(Cells(i, 18), 5) <> "Mail" And toDate - Date <= 7 Then
Set OutApp = CreateObject("Outlook.Application")
Set OutMail = OutApp.CreateItem(0)
toList = Cells(i, 7)
eSubject = "ACTION ITEM - " & Cells(i, 3) & " is due on " & Cells(i, 5)
eBody = "NOTICE for " & Cells(i, 6) & vbCrLf & vbCrLf & "You have task(s)coming due or ones that are past due. Please complete your tasks as soon as possible, then notify the Quality Administrator when the task is complete."
On Error Resume Next
With OutMail
.To = toList
.CC = ""
.BCC = ""
.Subject = eSubject
.Body = eBody
.bodyformat = 1
'.Display
.Display
End With
On Error GoTo 0
Set OutMail = Nothing
Set OutApp = Nothing
Cells(i, 9) = "Mail Sent " & Date + Time
End If
End If
Next i
ActiveWorkbook.Save
With Application
.ScreenUpdating = True
.EnableEvents = True
.DisplayAlerts = True
End With
End Sub
inside of your loop, put an if statement... fix the cell reference:
For i = 2 To lRow
If Cells(i,1).value <> "Completed" Then 'could also use Not Cells(i,1).value = "Completed"
'all of your regular code
End If
Next i
Edit1:
Update to use your code:
For i = 2 To lRow
If Cells(i,1).value <> "Completed" Then 'OPEN IT HERE
If Cells(i, 5) <> "" Then
toDate = Replace(Cells(i, 5), ".", "/")
If Left(Cells(i, 18), 5) <> "Mail" And toDate - Date <= 7 Then
Set OutApp = CreateObject("Outlook.Application")
Set OutMail = OutApp.CreateItem(0)
toList = Cells(i, 7)
eSubject = "ACTION ITEM - " & Cells(i, 3) & " is due on " & Cells(i, 5)
eBody = "NOTICE for " & Cells(i, 6) & vbCrLf & vbCrLf & "You have task(s)coming due or ones that are past due. Please complete your tasks as soon as possible, then notify the Quality Administrator when the task is complete."
On Error Resume Next
With OutMail
.To = toList
.CC = ""
.BCC = ""
.Subject = eSubject
.Body = eBody
.bodyformat = 1
'.Display
.Display
End With
On Error GoTo 0
Set OutMail = Nothing
Set OutApp = Nothing
Cells(i, 9) = "Mail Sent " & Date + Time
End If
End If
End If 'CLOSE IT HERE
Next i
A second way of doing it, with your existing If statement:
For i = 2 To lRow
If Cells(i, 5) <> "" Or Cells(i,1).value <> "Completed" Then
toDate = Replace(Cells(i, 5), ".", "/")
If Left(Cells(i, 18), 5) <> "Mail" And toDate - Date <= 7 Then
Set OutApp = CreateObject("Outlook.Application")
Set OutMail = OutApp.CreateItem(0)
toList = Cells(i, 7)
eSubject = "ACTION ITEM - " & Cells(i, 3) & " is due on " & Cells(i, 5)
eBody = "NOTICE for " & Cells(i, 6) & vbCrLf & vbCrLf & "You have task(s)coming due or ones that are past due. Please complete your tasks as soon as possible, then notify the Quality Administrator when the task is complete."
On Error Resume Next
With OutMail
.To = toList
.CC = ""
.BCC = ""
.Subject = eSubject
.Body = eBody
.bodyformat = 1
'.Display
.Display
End With
On Error GoTo 0
Set OutMail = Nothing
Set OutApp = Nothing
Cells(i, 9) = "Mail Sent " & Date + Time
End If
End If
Next i
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
So far i have got working a macro to send out emails to everyone in my excel list and it works fine except i need to add a couple more things to it:
1, Send the email to people ONLY if the date in Cells(r, 4).Value is between Today + 7 days and Today + 14 days otherwise skip that row.
2, If email has been sent change value of Cells(r, 20).Value from "False" to "True"
3, Skip rows were Cells(r, 20).Value is "True"
Heres how it loos so far:
Sub SetupAppointmentList()
' adds a list of appontments to the Calendar in Outlook
Dim olApp As Outlook.Application
Dim olAppItem As Outlook.AppointmentItem
Dim r As Long
DeleteNotices ' deletes previous test appointments
On Error Resume Next
Set olApp = GetObject("", "Outlook.Application")
On Error GoTo 0
If olApp Is Nothing Then
On Error Resume Next
Set olApp = CreateObject("Outlook.Application")
On Error GoTo 0
If olApp Is Nothing Then
MsgBox "Outlook is not available!"
Exit Sub
End If
End If
r = 10 ' first row with data in
While Len(Cells(r, 1).Formula) > 0
Set olAppItem = olApp.CreateItem(olAppointmentItem)
With olAppItem
.MeetingStatus = olMeeting
' set default appointment values
.Start = Now
.End = Now
.Subject = "No subject"
.Location = ""
.Body = ""
.ReminderSet = True
On Error Resume Next
.Recipients.Add Cells(r, 3).Value
.Recipients.ResolveAll
.Start = Cells(r, 4).Value + Cells(r, 5).Value
.End = Cells(r, 4).Value + Cells(r, 6).Value
.Subject = "Interview"
.Location = Cells(r, 13).Value + ", " + Cells(r, 14).Value
.Body = "Hi.... Blah Blah Blah"
.ReminderMinutesBeforeStart = 30
.Categories = "Notice"
On Error GoTo 0
.Save
.Display
'.Send
End With
r = r + 1
Wend
Set olAppItem = Nothing
Set olApp = Nothing
End Sub
Hope you can Help, Thanks in advance!
Rather than write the code for you here's what you do:
Get the content of Cells(r, 4) and use CDate to convert it to a date. Compare it to your start and end dates and if its in the range, continue.
Get content of (r, 20) and use CBool to get the bool value. Check and if OK continue.
After sending the email, just set Cells(r, 20) = true
Try that and see how it goes.