I am using the following code to loop through each row in the spreadsheet. whenever it meets the if condition, the reminder email will be automatically sent. But in this way, only one same email will be sent with all email address show in "To:". For privacy purpose,
I want the email to be sent to different receiver individually (send the email to one receiver a time). How should I update the loop to do this? Any thoughts?
Sub SendReminderMail()
Dim OutLookApp As Object
Dim OutLookMailItem As Object
Dim iCounter As Integer
Dim MailDest As String
Dim NumRows As Integer
Set OutLookApp = CreateObject("Outlook.Application")
Set OutLookMailItem = OutLookApp.CreateItem(0)
NumRows = ActiveSheet.UsedRange.Rows.Count
With OutLookMailItem
MailDest = ""
For iCounter = 1 To NumRows
If MailDest = "" And Cells(iCounter, 6).Offset(0, -2) = "Send Reminder" Then
MailDest = Cells(iCounter, 6).Value
ElseIf MailDest <> "" And Cells(iCounter, 6).Offset(0, -2) = "Send Reminder" Then
MailDest = MailDest & ";" & Cells(iCounter, 6).Value
End If
Next iCounter
.To = MailDest
.CC = CC
.BCC = BCC
.Subject = "FYI"
.Body = "Reminder: Some Message"
.Send
End With
Set OutLookMailItem = Nothing
Set OutLookApp = Nothing
End Sub
You just need to move the part of the code the creates and sends the email into the loop.
Sub SendReminderMail()
Dim OutLookApp As Object
Dim OutLookMailItem As Object
Dim iCounter As Integer
Dim MailDest As String
Dim NumRows As Integer
Set OutLookApp = CreateObject("Outlook.Application")
Set OutLookMailItem = OutLookApp.CreateItem(0)
NumRows = ActiveSheet.UsedRange.Rows.Count
For iCounter = 1 To NumRows
MailDest = ""
If Cells(iCounter, 6).Offset(0, -2) = "Send Reminder" Then
Set OutLookMailItem = OutLookApp.CreateItem(0)
With OutLookMailItem
MailDest = Cells(iCounter, 6).Value
.To = MailDest
.CC = CC
.BCC = BCC
.Subject = "FYI"
.Body = "Reminder: Some Message"
.Send
Set OutLookMailItem = Nothing
End With
End If
Next iCounter
Set OutLookApp = Nothing
End Sub
Related
I have this code that I have cobbled together but, sadly I am stuck I can’t seem to work out how to only have the email addresses for overdue entries in the BCC.
I want it to create a single email to multiple email addresses from a list of emails that have a due date that is overdue and a previous email hasn't already been sent.
Sub Over_due()
Dim OutApp As Object
Dim OutMail As Object
Dim lLastRow As Long
Dim lRow As Long
Dim rng As Range
strbody = "Text goes here"
lLastRow = Cells(Rows.Count, 3).End(xlUp).Row
For lRow = 2 To lLastRow
If Cells(lRow, 6) <> "Email Sent" Then
If Cells(lRow, 5) <= Date Then
Set xOutlook = CreateObject("Outlook.Application")
Set xMailItem = xOutlook.CreateItem(0)
For Each rng In Range("C:C")
If rng.Value Like "*#*" Then
If xEmailAddr = "" Then
xEmailAddr = rng.Value
Else
xEmailAddr = xEmailAddr & ";" & rng.Value
End If
End If
Next
On Error Resume Next
With xMailItem
.To = ""
.CC = ""
.BCC = xEmailAddr
.Subject = Range("A1").Value
.HTMLBody = strbody
'.Attachments.Add
.Display
End With
MsgBox "E-mail successfully created", 64
Application.DisplayAlerts = False
Set Mail_Object = Nothing
Cells(lRow, 6) = "Sent email"
Cells(lRow, 7) = "" & Now()
End If
End If
Next
Set OutApp = Nothing
End Sub
I use a sub which automatically creates emails. and call it from various other subs - might come in handy:
Sub SendEmail(Optional ToAddresses As String, Optional CcAddresses As String, _
Optional BccAddresses As String, Optional Subject As String, _
Optional Body As String, Optional AttachFiles As Variant = False, Optional AutoSend As Boolean = False)
'RULES:
' Where there are multiple Addresses in ToAddresses, CCAddresses
' etc, they have to be separated by a semicolon
' AttachFiles should either be a string containing the full
' filename including the path, or (for multiple files) an array
' of same.
' Body can be HTML or just plain text.
Dim OutApp As Object
Dim OutMail As Object
Set OutApp = CreateObject("Outlook.Application")
Set OutMail = OutApp.CreateItem(0)
With OutMail
.to = ToAddresses
.CC = CcAddresses
.Bcc = BccAddresses
.Subject = Subject
If Body Like "*</*>*" Then
.HtmlBody = Body
Else
.Body = Body
End If
If Not AttachFiles = False Then
If IsArray(AttachFiles) Then
For x = LBound(AttachFiles) To UBound(AttachFiles)
.Attachments.Add (AttachFiles(x))
Next
Else
.Attachments.Add (AttachFiles)
End If
End If
If AutoSend = True Then
.Send
Else
.Display
End If
End With
Set OutMail = Nothing
Set OutApp = Nothing
End Sub
It's not totally my code, I adapted it from here.
It won't completely solve your problem, but it might condense it down to something simpler and more like:
Sub OverDue()
Dim strBody as String
Dim Row as Long
Dim lLastRow as Long
StrBody = "Text here"
lLastRow = UsedRange.Rows.Count
For a = 2 to lLastRow
If Cells(a, 6) <> "Email Sent" And Cells(a, 5)<= Date Then 'This checks each row to see if that person needs an email
' DO STUFF HERE
' Either Call the other sub separately each time
' (which can allow for more personalised messages, like a mail merge),
' or add the person's email address to a string and call the sub
' after the loop.
Next
End Sub
Over to you to work out the rest of the details though!!
I fixed your code like that
Sub Over_due()
Dim OutApp As Object
Dim OutMail As Object
Dim lLastRow As Long
Dim lRow As Long
Dim rng As Range
Dim strbody As String
Dim xOutlook
Dim xMailItem
Dim xEmailAddr
strbody = "Text goes here"
lLastRow = Cells(Rows.Count, 3).End(xlUp).Row
For lRow = 2 To lLastRow
If Cells(lRow, 6) <> "Email Sent" Then
If Cells(lRow, 5) <= Date Then
Set xOutlook = CreateObject("Outlook.Application")
Set xMailItem = xOutlook.CreateItem(0)
' For Each rng In Range("C:C")
' If rng.Value Like "*#*" Then
' If xEmailAddr = "" Then
' xEmailAddr = rng.Value
' Else
' xEmailAddr = xEmailAddr & ";" & rng.Value
' End If
' End If
' Next
'Do you really want to have all emails addresses in BCC because thats what you are doing
'I changed the above code to the following lines which will not take the complete column
Set rng = Range("C2:C" & lRow)
xEmailAddr = Join(WorksheetFunction.Transpose(rng), ",")
On Error Resume Next
With xMailItem
.To = ""
.CC = ""
.BCC = xEmailAddr
.Subject = Range("A1").Value
.HTMLBody = strbody
'.Attachments.Add
.Display
End With
MsgBox "E-mail successfully created", 64
Application.DisplayAlerts = False
' I changed that to Email Sent otherwise it will create the mai over and over again
Cells(lRow, 6) = "Email Sent"
Cells(lRow, 7) = "" & Now()
End If
End If
Next
Set OutApp = Nothing
End Sub
Looking for help with sending emails to a list of people. My code has a simple loop and grabs the value each time through of where to send the email. While testing, the first email will always get sent. After that, the 2nd time through I get error on ".To"
Run-time error - '-2147221238 (8004010a):
The item has been moved or deleted.
This is puzzling to me because the code does accurately grab the next email value?
The emails need to be sent one by one, instead of adding the recipients to a list of bcc. Is this possible with VBA? Thanks in advance!
Sub TestingAgain()
'Setting up the Excel variables.
Dim outApp As Object
Dim outMailItem As Object
Dim iCounter As Integer
Dim sDest As String
Dim sName As String
'Create the Outlook application and the empty email.
Set outApp = CreateObject("Outlook.Application")
Set outMailItem = outApp.CreateItem(0)
With outMailItem
sDest = ""
For i = 2 To WorksheetFunction.CountA(Columns(1))
If i <> "" Then
'Grab first name and email
sDest = Cells(i, 5).Value
sName = Cells(i, 1).Value
'Send each email
.To = sDest
.Subject = "FYI"
.htmlbody = "Some stuff"
.Send
Else
MsgBox ("Error")
End If
Next i
End With
'Clean up the Outlook application.
Set outMailItem = Nothing
Set outApp = Nothing
End Sub
When you send the e-mail, the mailItem instance is done and not available anymore. Refactor your code like :
Sub TestingAgain()
'Setting up the Excel variables.
Dim outApp As Object
Dim outMailItem As Object
Dim iCounter As Integer
Dim sDest As String
Dim sName As String
'Create the Outlook application and the empty email.
Set outApp = CreateObject("Outlook.Application")
sDest = ""
For i = 2 To WorksheetFunction.CountA(Columns(1))
If i <> "" Then
'/ Create the mail item instance.
Set outMailItem = outApp.CreateItem(0)
With outMailItem
'Grab first name and email
sDest = Cells(i, 5).Value
sName = Cells(i, 1).Value
'Send each email
.To = sDest
.Subject = "FYI"
.htmlbody = "Some stuff"
.send
'/ Once sent, mail item is no more available.
End With
Else
MsgBox ("Error")
End If
Next
'Clean up the Outlook application.
Set outMailItem = Nothing
Set outApp = Nothing
End Sub
I am an absolute beginner and try to facilitate a few tasks in my colleagues daily work. I want to create a code that sends reminder mails with information from an excel file. The idea is that Excel should check every relevant row from row 12 on and check if there is an "x" written in a column that marks for which row I would like to send a reminder.
With the code below I can generate all the emails, but I have difficulties where and how to include the check for if ('If Cells(s, 6).Value = "x" Then') so that that Excel continues through all the rows that are filled out.
Many thanks for your help!
Sub SendReminderMail()
Dim s As Long
Dim OutLookApp As Object
Dim OutLookMailItem As Object
Dim iCounter As Integer
Dim MailDest As String
If MsgBox("Are you sure?", vbYesNo) = vbNo Then Exit Sub
Set OutLookApp = CreateObject("Outlook.application")
Set OutLookMailItem = OutLookApp.CreateItem(0)
s = 12
Do Until Trim$(Cells(s, 1).Value) = ""
Set OutLookMailItem = OutLookApp.CreateItem(0)
With OutLookMailItem
.To = Cells(s, 5).Value
.Subject = "Reminder: " & Cells(1, 7).Value
.Body = "Text, " & vbCrLf & vbCrLf & "Text'" & Cells(s, 2).Value
s = s + 1
.Display
End With
Loop
End Sub
Since you are checking every row with the Do...Loop then you need to check the if inside that loop. I've moved the increment to s outside the If so that it happens whether or not you create a mail item. Otherwise you'd only change rows if there was a mail item to send, and that means you'd be stuck looping on a row where there was no "x".
Sub SendReminderMail()
Dim s As Long
Dim OutLookApp As Object
Dim OutLookMailItem As Object
Dim iCounter As Integer
Dim MailDest As String
If MsgBox("Are you sure?", vbYesNo) = vbNo Then Exit Sub
Set OutLookApp = CreateObject("Outlook.application")
Set OutLookMailItem = OutLookApp.CreateItem(0)
s = 12
Do Until Trim$(Cells(s, 1).Value) = ""
If Cells(s,6).Value = "x" Then
Set OutLookMailItem = OutLookApp.CreateItem(0)
With OutLookMailItem
.To = Cells(s, 5).Value
.Subject = "Reminder: " & Cells(1, 7).Value
.Body = "Text, " & vbCrLf & vbCrLf & "Text'" & Cells(s, 2).Value
.Display
End With
End If
s = s + 1
Loop
End Sub
Sub SendReminderMail()
Dim OutlookApp As Object
Dim OutLookMailItem As Object
Dim iCounter As Integer
Dim MailDest As String
Set OutlookApp = CreateObject("Outlook.application")
Set OutLookMailItem = OutlookApp.CreateItem(0)
With OutLookMailItem
MailDest = ""
For iCounter = 1 To WorksheetFunction.CountA(Columns(34))
If MailDest = "" And Cells(iCounter, 34).Offset(0, -1) = "Send Reminder" Then
MailDest = Cells(iCounter, 34).Value
ElseIf MailDest <> "" And Cells(iCounter, 34).Offset(0, -1) = "Send Reminder" Then
MailDest = MailDest & ";" & Cells(iCounter, 34).Value
End If
Next iCounter
.BCC = MailDest
.Subject = "ECR Notification"
.HTMLBody = "Reminder: This is a test for an automatic ECR email notification. Please complete your tasks for ECR#"
.Send
End With
Set OutLookMailItem = Nothing
Set OutlookApp = Nothing
End Sub
Need code to email the values in columns AE with the "set reminder" text
GD mjac,
You are still shy with your information...?
Your presented code collects all addresses and subsequently sends a single message ? I would expect, based on your example sheet/data that you would want to send an email to each recipient for each ECR code that is 'open' ?
So assuming the following:
You want to send an email for every line where the "Send reminder" is
true
The email addresses in columns "AH" will differ for every line ?
In your code you use the Outlook.Application objects Set OutlookApp = CreateObject("Outlook.application"), be careful with opening application type objects and be sure to ensure they will be closed in the event the code finishes or when an error is triggered, otherwise you could potentially end up with a number of Outlook instances that are 'running' using valuable reqources. The below code has some basic error handling to ensure the OutlookApp object is closed if no longer required.
Setup your Workbook as follows:
In VB Editor under Tools|References find 'Microsoft Outlook xx.x Object Library', where xx.x represents the version of Outlook that you are working with. (see also: https://msdn.microsoft.com/en-us/library/office/ff865816.aspx) This will make for easier coding as you get intellisense suggestions for your objects.
Declare OutlookApp as public, above all other subs/functions etc. etc.
(i.e. at the top of your 'coding' window)
Public OutlookApp As Outlook.Application
your sendReminderMail() sub
Sub SendReminderMail()
Dim iCounter As Integer
Dim MailDest As String
Dim ecr As Long
On Error GoTo doOutlookErr:
Set OutlookApp = New Outlook.Application
For iCounter = 1 To WorksheetFunction.CountA(Columns(34))
MailDest = Cells(iCounter, 34).Value
ecr = Cells(iCounter, 34).Offset(0, -3).Value
If Not MailDest = vbNullString And Cells(iCounter, 34).Offset(0, -1) = "Send Reminder" Then
sendMail MailDest, ecr
MailDest = vbNullString
End If
Next iCounter
'basic errorhandling to prevent Outlook instances to remain open in case of an error.
doOutlookErrExit:
If Not OutlookApp Is Nothing Then
OutlookApp.Quit
End If
Exit Sub
doOutlookErr:
MsgBox Err.Description, vbOKOnly, Err.Source & ":" & Err.Number
Resume doOutlookErrExit
End Sub
added sendMail Function:
Function sendMail(sendAddress As String, ecr As Long) As Boolean
'Initiate function return value
sendMail = False
On Error GoTo doEmailErr:
'Initiate variables
Dim OutLookMailItem As Outlook.MailItem
Dim htmlBody As String
'Create the mail item
Set OutLookMailItem = OutlookApp.CreateItem(olMailItem)
'Create the concatenated body of the mail
htmlBody = "<html><body>Reminder: This is a test for an automatic ECR email notification.<br>" & _
"Please complete your tasks for ECR#" & CStr(ecr) & "</body></html>"
'Chuck 'm together and send
With OutLookMailItem
.BCC = sendAddress
.Subject = "ECR Notification"
.HTMLBody = htmlBody
.Send
End With
sendMail = True
doEmailErrExit:
Exit Function
doEmailErr:
MsgBox Err.Description, vbOKOnly, Err.Source & ":" & Err.Number
Resume doEmailErrExit
End Function
I've got the following script which should for all that I can see, work without issue (and in fact at one point yesterday was working - but I must have inadvertently changed something when trying to clean up the code because it's no longer working today).
Perhaps another set of eyes can help me. I have a rule setup to set these emails into their own folder and run the script in Outlook. That works without issue - the issue comes from the script itself.
The subject of the emails that come in that get filtered are generally something like this:
"Ticket: 328157 School: BlahBlah Issues: Problems with flux capacitor"
The idea is that the script will create a task with the appropriate priority level and put it in the appropriate category (and include just the stuff in the subject after 'School"' because the ticket # is not important).
Here is the script:
Sub MakeTaskFromMail(MyMail As Outlook.MailItem)
Dim strID As String
Dim olNS As Outlook.NameSpace
Dim olMail As Outlook.MailItem
Dim objTask As Outlook.TaskItem
'Get Specific Email based on ID
strID = MyMail.EntryID
Set olNS = Application.GetNamespace("MAPI")
Set olMail = olNS.GetItemFromID(strID)
Set objTask = Application.CreateItem(olTaskItem)
'**************************
'*****SET TASK SUBJECT*****
'**************************
Dim sInput As String
Dim sOutput As String
'get the email subject
sInput = olMail.Subject
'get all the text after School: in the subject
sOutput = Mid(sInput, InStr(sInput, "School:") + 8)
Dim priorityUrgentString As String
Dim priorityHighString As String
Dim priorityMediumString As String
Dim priorityLowString As String
'Set Priority Strings to check for to determine category
priorityUrgentString = "Priority: Urgent"
priorityHighString = "Priority: High Priority"
priorityMediumString = "Priority: Medium"
priorityLowString = "Priority: Project"
'check to see if ticket is Urgent
'if urgent - due date is today and alert is set for 8am
If InStr(olMail.Body, priorityUrgentString) <> 0 Then
With objTask
.Subject = sOutput
.DueDate = olMail.SentOn
.Body = olMail.Body
.Categories = "Urgent"
.Importance = olImportanceHigh
.ReminderSet = True
.ReminderTime = objTask.DueDate
End With
'check to see if ticket is High Priority
'if High Priority - due date is today - alert is set for 8am
ElseIf InStr(olMail.Body, priorityHighString) <> 0 Then
With objTask
.Subject = sOutput
.DueDate = olMail.SentOn + 2
.Body = olMail.Body
.Categories = "High"
.Importance = olImportanceHigh
.ReminderSet = True
.ReminderTime = objTask.DueDate + 2
End With
'check to see if its a medium priority
'if medium - due date is set for 7 days, no alert
ElseIf InStr(olMail.Body, priorityMediumString) <> 0 Then
With objTask
.Subject = sOutput
.DueDate = olMail.SentOn + 7
.Body = olMail.Body
.Categories = "Medium"
.Importance = olImportanceNormal
End With
'check to see if its a project priority
'if project - due date is set for 21 days, no alert
ElseIf InStr(olMail.Body, priorityLowString) <> 0 Then
With objTask
.Subject = sOutput
.DueDate = olMail.SentOn + 21
.Body = olMail.Body
.Categories = "Project"
.Importance = olImportanceLow
End With
End If
'Copy Attachments
Call CopyAttachments(olMail, objTask)
'Save Task
objTask.Save
Set objTask = Nothing
Set olMail = Nothing
Set olNS = Nothing
End Sub
Sub CopyAttachments(objSourceItem, objTargetItem)
Set fso = CreateObject("Scripting.FileSystemObject")
Set fldTemp = fso.GetSpecialFolder(2) ' TemporaryFolder
strPath = fldTemp.Path & "\"
For Each objAtt In objSourceItem.Attachments
strFile = strPath & objAtt.FileName
objAtt.SaveAsFile strFile
objTargetItem.Attachments.Add strFile, , , objAtt.DisplayName
fso.DeleteFile strFile
Next
Set fldTemp = Nothing
Set fso = Nothing
End Sub
What I can see without running the script is this:
You will have to save the TaskItem, after setting it (use .Save as the last line within the With)
Also, you will probably have to set the ReminderTime matching the mailitem
.ReminderTime = olMail.SentOn
instead of
.ReminderTime = objTask.DueDate
because it isn't saved yet