I can send email to multiple recipients with a click of a button in Excel with this code.
The problem comes when marking it with time. If I send email to one recipient the whole column will be marked with the time and mark of that one recipient and ignore the others.
This is my code in Module1 and a class called Class1
This is the code in Module1
Sub Button4_Click()
Dim OutApp As Object
Dim OutMail As Object
Dim lLastRow As Long
Dim lRow As Long
Dim sSendTo As String
Dim sSendCC As String
Dim sSendBCC As String
Dim sSubject As String
Dim sTemp As String
Set OutApp = CreateObject("Outlook.Application")
Set itmevt.itm = Nothing
OutApp.Session.Logon
sSendTo = Range("D3")
sSendCC = ""
sSendBCC = ""
sSubject = "Due date reached"
lLastRow = Cells(Rows.Count, 3).End(xlUp).Row
For lRow = 3 To lLastRow
If Cells(lRow, 5) <> "Email sent" Then
If Cells(lRow, 3) <= Date Then
Set OutMail = OutApp.CreateItem(0)
Set itmevt.itm = OutMail
With OutMail
.To = sSendTo
If sSendCC > "" Then .CC = sSendCC
If sSendBCC > "" Then .BCC = sSendBCC
.Subject = sSubject
sTemp = "Hello!" & vbCrLf & vbCrLf
sTemp = sTemp & "The due date has been reached "
sTemp = sTemp & "for this project:" & vbCrLf & vbCrLf
sTemp = sTemp & " " & Cells(lRow, 2)
sTemp = sTemp & vbCrLf & vbCrLf & " Please take the appropriate"
sTemp = sTemp & " action." & vbCrLf
sTemp = sTemp & "Regards," & vbCrLf
sTemp = sTemp & "Danial " & vbCrLf
.Body = sTemp
.Display
End With
Set OutMail = Nothing
End If
End If
Next lRow
Set OutApp = Nothing
End Sub
This is the code in Class1
Option Explicit
Public WithEvents itm As Outlook.MailItem
Private Sub itm_Close(Cancel As Boolean)
Dim lLastRow As Long
Dim lRow As Long
Dim blnSent As Boolean
On Error Resume Next
blnSent = itm.Sent
lLastRow = Cells(Rows.Count, 3).End(xlUp).Row
For lRow = 3 To lLastRow
If Cells(lRow, 5) <> "Email sent" Then
If Cells(lRow, 3) <= Date Then
If Err.Number = 0 Then
Cells(lRow, 5) = "Email not sent"
Cells(lRow, 6) = "X"
Cells(lRow, 6).Interior.ColorIndex = 38
Else
Cells(lRow, 5) = "Email sent"
Cells(lRow, 6) = Now()
End If
End If
End If
Next lRow
End Sub
Try to sSendTo = Range("D3").value, if it's not worked. Please process the sSendTo=Join(split(range("D3").value,";"),";")
Related
I am trying to create a macro to send automated reminders.
I am sending below the two macros:
Sub Auto_Open()
Dim vResp As Variant, dTime As Date
vResp = MsgBox("Inviare email ora?", vbYesNo)
If vResp = 6 Then 'YES
Call EmailReminder
ElseIf vResp = 7 Then 'NO
dTime = CDate(InputBox("Send email at:", , Time + TimeValue("00:00:10")))
Do Until Time = dTime 'OR = #8:00:00 AM#
DoEvents
Loop
Call EmailReminder
End If
End Sub
Sub EmailReminder()
Dim oOL As Outlook.Application, oMail As Outlook.MailItem, oNS As Outlook.Namespace
Dim oMapi As Outlook.MAPIFolder, oExpl As Outlook.Explorer
Dim sBody As String, dDate As Date
Dim oWS As Worksheet, r As Long, i As Long, sStart As String
Set oWS = Foglio1
Set oOL = New Outlook.Application
Set oExpl = oOL.ActiveExplorer
If TypeName(oExpl) = "Nothing" Then
Set oNS = oOL.GetNamespace("MAPI")
Set oMapi = oNS.GetDefaultFolder(olFolderInbox)
Set oExpl = oMapi.GetExplorer
End If
With oWS.Range("E1")
r = .CurrentRegion.Rows.Count
For i = 1 To r
dDate = .Cells(i, 1)
sBody = "Oggi è il compleanno di" & .Cells(i, 2) & dDate & .Cells(i, -4) & " " & .Cells(i, -3) & vbCrLf & "Facciamo i nostri auguri!"
If Date = dDate Or Date = Int(dDate) Then ' Use INT to eliminate time info
Set oMail = oOL.CreateItem(oIMailItem)
With oMail
.Recipients.Add "umberto.roselli#openfiber.it" 'Indirizzo ricevente
.Subject = "Nuovo compleanno oggi:" & .Cells(i, -4) & " " & .Cells(i, -3) & .Body = sBody: .Send
End With
End If
Next i
End With
MsgBox "Messaggio email inviato correttamente!"
End Sub
I keep getting, however, on the second macro the error Run-Time 13: Type not matching but it doesn't give me any indication where the error is.
Can you help me out?
Thank you very much in advance
Fyi
Private Sub Workbook_Open()
Dim i As Long
Dim OutApp, OutMail As Object
Dim strto, strcc, strbcc, strsub, strbody As String
Set OutApp = CreateObject("Outlook.Application")
OutApp.Session.Logon
Set OutMail = OutApp.CreateItem(0)
For i = 2 To Range("e65536").End(xlUp).Row
If Cells(i, 8) <> "Y" Then
If Cells(i, 5) - 7 < Date Then
strto = Cells(i, 7).Value 'email address
strsub = Cells(i, 1).Value & " " & Cells(i, 2).Value & " compleanno il " & Cells(i, 5).Value 'email subject
strbody = "Il compleanno di " & Cells(i, 1).Value & " " & Cells(i, 2).Value & " sarà il " & Cells(i, 5).Value & vbNewLine 'email body
With OutMail
.To = strto
.Subject = strsub
.Body = strbody
.Send
End With
Cells(i, 8) = "Mail Sent " & Now()
Cells(i, 9) = "Y"
End If
End If
Next
Set OutMail = Nothing
Set OutApp = Nothing
End Sub
Hello Everyone i was wondering if anyone can help me resolve my problem., i have got code which i found from the net which is working absolutely perfect however only problem is that when there is more than one due date in the column it will send email each time instead of sending all due date and names in One email at same time. Names it is on column A, Expiry Date it is in column E, and email stamp as sent in Column F, below its the code.
Private Sub Workbook_Open()
Dim Email As String, Subj As String, Msg As String, wBox As String
Dim RowNo As Long, i As Long, ky As Variant, cad As Variant
Dim wsEmail As Worksheet, OutApp As Object, OutMail As Object, dic As Object
Set wsEmail = ThisWorkbook.Sheets("Tracker")
Set dic = CreateObject("scripting.dictionary")
With wsEmail
For RowNo = 2 To .Cells(.Rows.Count, "A").End(xlUp).Row
If .Cells(RowNo, "E") <> "" Then
If .Cells(RowNo, "F") = "" And .Cells(RowNo, "E") <> "" And .Cells(RowNo, "E") <= Date + 60 Then
If dic.exists(.Cells(RowNo, "F").Value) Then
dic(.Cells(RowNo, "A").Value) = dic(.Cells(RowNo, "A").Value) & RowNo & "|"
Else
dic(.Cells(RowNo, "A").Value) = RowNo & "|"
End If
End If
End If
Next
For Each ky In dic.keys
cad = Left(dic(ky), Len(dic(ky)) - 1)
cad = Split(cad, "|")
wBox = ""
dBox = ""
For i = 0 To UBound(cad)
wBox = wBox & " " & wsEmail.Cells(cad(i), "A")
dBox = wsEmail.Cells(cad(i), "E")
.Cells(cad(i), "F") = "Sent"
.Cells(cad(i), "G") = Environ("username")
.Cells(cad(i), "H") = "E-mail sent on: " & Now()
Next
On Error Resume Next
Set OutApp = GetObject("Outlook.Application")
On Error GoTo 0
If OutApp Is Nothing Then Set OutApp = CreateObject("Outlook.Application")
Do: Loop Until Not OutApp Is Nothing
Set OutMail = OutApp.CreateItem(0)
With OutMail
Subj = wBox & Space(1) & "from will expire soon"
Msg = "Hi" & vbCrLf & vbCrLf _
& "This is an automated e-mail to let you know that" & wBox & Space(1) & " will expire as follow;" & vbCrLf & vbCrLf _
& "Expiry date:" & dBox & vbCrLf & vbCrLf & "Many Thanks " & vbCrLf _
& vbCrLf & "Kind Regards" & vbCrLf & vbCrLf & Environ("username")
.To = "Sent to"
.CC = ""
.BCC = ""
.Subject = Subj
.ReadReceiptRequested = False
.Body = Msg
.Display
End With
mystring = ("Email has been sent for below staff;") & _
vbCrLf & vbCrLf & ky
MsgBox mystring
Set OutApp = Nothing
Set OutMail = Nothing
Next
End With
End Sub
is there any way to do this?
This should get you started.
Read the code's comments and adjust it to fit your needs.
Private Sub SendEmails()
Dim trackerSheet As Worksheet
Set trackerSheet = ThisWorkbook.Worksheets("CTCTracker")
Dim lastRow As Long
lastRow = trackerSheet.Cells(trackerSheet.Rows.Count, "A").End(xlUp).Row
Dim trackerRange As Range
Set trackerRange = trackerSheet.Range("A5:A" & lastRow)
' Declare boolean to check if there are any expiring names
Dim anyExpiring As Boolean
Dim nameCell As Range
For Each nameCell In trackerRange
' Check: 1) There is a expiring date
' 2) Email not sent yet
' 3) Expiring date less than today + 60 días
If nameCell.Offset(0, 4).Value <> "" And _
nameCell.Offset(0, 5).Value = "" And _
nameCell.Offset(0, 4).Value <= Date + 60 Then
' Store names and expiring dates into array
Dim infoArray() As Variant
Dim counter As Long
ReDim Preserve infoArray(counter)
infoArray(counter) = Array(nameCell.Value, nameCell.Offset(0, 4).Value)
counter = counter + 1
' Stamp action log
nameCell.Offset(0, 5).Value = "Sent"
nameCell.Offset(0, 6).Value = Environ$("username")
nameCell.Offset(0, 7).Value = "E-mail sent on: " & Now()
' To be able to check later
anyExpiring = True
End If
Next nameCell
' Exit if there are not expiring contacts
If Not anyExpiring Then
MsgBox "There are not expiring contacts"
Exit Sub
End If
' Prepare message
Dim namesList As String
For counter = 0 To UBound(infoArray)
namesList = namesList & infoArray(counter)(0) & vbTab & vbTab & " | " & vbTab & vbTab & infoArray(counter)(1) & vbNewLine
Next counter
Dim emailBodyTemplate As String
emailBodyTemplate = "This is an automated e-mail to let you know that the following CTC will expire as follow:" & vbCrLf & vbCrLf & _
"Name" & vbTab & vbTab & vbTab & " | " & vbTab & vbTab & vbTab & " CTC Expiry date" & vbCrLf & _
"<namesList>" & vbCrLf & vbCrLf & _
"Many Thanks " & vbCrLf & _
vbCrLf & "Kind Regards" & vbCrLf & vbCrLf & Environ("username")
Dim emailBody As String
emailBody = Replace(emailBodyTemplate, "<namesList>", namesList)
' Start outlook (late bound)
Dim outApp As Object
On Error Resume Next
Set outApp = GetObject("Outlook.Applicatin")
On Error GoTo 0
' If outlook is not running, start an instance
If outApp Is Nothing Then Set outApp = CreateObject("Outlook.Application")
Do: Loop Until Not outApp Is Nothing
' Compose email
Dim outMail As Object
Set outMail = outApp.CreateItem(0)
With outMail
.To = "Sent to"
.CC = ""
.BCC = ""
.Subject = "CTC will expire soon"
.ReadReceiptRequested = False
.Body = emailBody
.Display
End With
' Display message to user
Dim staffMessage As String
staffMessage = ("Email has been sent for below staff")
MsgBox staffMessage
' Clean up
Set outApp = Nothing
Set outMail = Nothing
End Sub
Let me know if it works
I have a sample sheet
I have a module that runs through the list in a loop within another loop, checking for duplicate names and then grouping the names together to send an email with an attachment based on Column D (Division).
Sample 4 would get one email with 3 attachments.
I have been asked to build in the ability to exclude people based on a value (I chose yes or no, column C) before running the module.
Reason being that if the list is long (over 1000 names) to set it before generating the emails. I would build in a trigger to set that value, but it is apparently an arbitrary decision made by the senders in a dept.
I have tried to build an IF statement into the loop as shown below but it is as if the If statement is coming out as not being true (I stepped through).
Which means all the With Outmail objects will not work.
I was able to get it to work by using the if statement with a for/next setup on its own (no loops), but cannot get it to work with the loop, which is the more important piece.
Here is the main piece of code. The main loop and then the if statement to account for the yes or no values:
Do While r <= rng.Rows.Count
If rng.Cells(r, 3).Value Like "?*#?*.?*" And LCase(rng.Cells(r, 3)) = "yes" Then
Set OutMail = OutApp.CreateItem(0)
End If
And here is the full sub:
Sub EmailDivisions()
Dim OutApp As Object
Dim OutMail As Object
Dim cell, lookrng As Range
Dim strDir As String
Dim strFilename As String
Dim sigString As String
Dim strBody As String
Dim strName As Variant
Dim strName1 As Variant
Dim strDept As Variant
Dim strName2 As String
Dim strName3 As Variant
Application.ScreenUpdating = False
Set OutApp = CreateObject("Outlook.Application")
sigString = Environ("appdata") & _
"\Microsoft\Signatures\Divisions.htm"
If Dir(sigString) <> "" Then
signature = GetBoiler(sigString)
Else
signature = ""
End If
Set rng = ActiveSheet.UsedRange
r = 2
Do While r <= rng.Rows.Count
If rng.Cells(r, 3).Value Like "?*#?*.?*" And LCase(rng.Cells(r, 3)) = "yes" Then
Set OutMail = OutApp.CreateItem(0)
End If
Set strName = rng.Cells(r, 1)
Set strDept = rng.Cells(r, 4)
strName2 = Left(strName, InStr(strName & " ", " ") - 1)
With OutMail
strFilename = Dir("\\Divisons\1a*" & strDept & "*")
.SentOnBehalfOfName = "divisionalsend#xyz.org"
.To = rng.Cells(r, 2).Value
.Subject = "Monthly Divisional Report for " & strDept
.HTMLBody = "<Font Face=calibri>" & "Dear " & strName2 & ",<br><br>" & signature
.Attachments.Add strDir & strFilename
'See if the next row is for the same sender. If so, process that
'row as well. And then keep doing it until no more rows match
Do While rng.Cells(r, 2).Value = rng.Cells(r + 1, 2)
r = r + 1
Set strDept = rng.Cells(r, 4)
strfilename1 = Dir("\\Divisions\1a*" & strDept & "*")
.Subject = "Monthly Divisional Report for Your Departments"
.Attachments.Add strDir & strfilename1
Loop
.Display
End With
Set OutMail = Nothing
r = r + 1
Loop
Set OutApp = Nothing
End Sub
Function GetBoiler(ByVal sFile As String) As String
Dim FSO As Object
Dim ts As Object
Set FSO = CreateObject("Scripting.FileSystemObject")
Set ts = FSO.GetFile(sFile).OpenAsTextStream(1, -2)
GetBoiler = ts.ReadAll
ts.Close
End Function
Figured it out, here is the final sub:
Sub EmailDivisions()
Dim OutApp As Object
Dim OutMail As Object
Dim cell, lookrng As Range
Dim strDir As String
Dim strFilename As String
Dim sigString As String
Dim strBody As String
Dim strName As Variant
Dim strName1 As Variant
Dim strDept As Variant
Dim strName2 As String
Dim strName3 As Variant
Application.ScreenUpdating = False
Set OutApp = CreateObject("Outlook.Application")
sigString = Environ("appdata") & _
"\Microsoft\Signatures\Divisions.htm"
If Dir(sigString) <> "" Then
signature = GetBoiler(sigString)
Else
signature = ""
End If
Set rng = ActiveSheet.UsedRange
r = 2
Do While r <= rng.Rows.Count
Debug.Print LCase(rng.Cells(r, 2))
If Cells(r, 2).Value Like "?*#?*.?*" And LCase(Cells(r, 3)) = "yes" Then
Set OutMail = OutApp.CreateItem(0)
ElseIf Cells(r, 2).Value Like "?*#?*.?*" And LCase(Cells(r, 3)) = "no" Then GoTo ContinueLoop
End If
Set strName = Cells(r, 1)
Set strDept = Cells(r, 4)
strName2 = Left(strName, InStr(strName & " ", " ") - 1)
With OutMail
strFilename = Dir("\\Divisons\1a*" & strDept & "*")
.SentOnBehalfOfName = "divisionalsend#xyz.org"
.To = Cells(r, 2).Value
.Subject = "Monthly Divisional Report for " & strDept
.HTMLBody = "<Font Face=calibri>" & "Dear " & strName2 & ",<br><br>" & signature
.Attachments.Add strDir & strFilename
.display
'See if the next row is for the same sender. If so, process that
'row as well. And then keep doing it until no more rows match
Do While rng.Cells(r, 2).Value = rng.Cells(r + 1, 2)
r = r + 1
Set strDept = Cells(r, 4)
strfilename1 = Dir("\\Divisions\1a*" & strDept & "*")
.Subject = "Monthly Divisional Report for Your Departments"
.Attachments.Add strDir & strfilename1
.Display
ContinueLoop:
Loop
End With
Set OutMail = Nothing
r = r + 1
Loop
Set OutApp = Nothing
End Sub
Function GetBoiler(ByVal sFile As String) As String
Dim FSO As Object
Dim ts As Object
Set FSO = CreateObject("Scripting.FileSystemObject")
Set ts = FSO.GetFile(sFile).OpenAsTextStream(1, -2)
GetBoiler = ts.ReadAll
ts.Close
End Function
I have the mention code and it works all well with unique records, but the only problem is it sends multiple emails to 1 email id.
Email ID's are n column W (1st record is w6) and body of the mail is in column x6
have merge the body with code "wsht.cells(i, 25) = sbody"
any idea as who will this work were it wil send 1 email
for eg:- in w7 email id is xxx#gmail.com and in w10 email id is xxx#gmail.com
currently the code# send 2 mails, but it should send only 1 email to xxx#gmail.com
Any idea or update.
Private Sub CommandButton3_Click()
Dim OutApp As Object
Dim OutMail As Object
Set OutApp = CreateObject("Outlook.Application")
With Application
.EnableEvents = False
.ScreenUpdating = False
End With
Dim wSht As Worksheet
Dim LastRow As Long, lCuenta As Long
Dim i As Integer, k As Integer
Dim sTo As String, sSbject As String, sBody As String
Set wSht = ActiveSheet
LastRow = Cells(Rows.Count, 1).End(xlUp).Row
For i = 6 To LastRow
lCuenta = Application.WorksheetFunction.CountIf(Range("W6:W" & i), Range("W" & i))
If lCuenta = 1 Then
ssubject = "PD Call Back"
sTo = wSht.Cells(i, 1)
sBody = wSht.Cells(i, 24)
For k = i To LastRow
If wSht.Cells(i, 1).Value = wSht.Cells(k + 1, 1).Value Then
sBody = sBody & vbNewLine & wSht.Cells(k + 1, 24).Value
End If
wSht.Cells(i, 25) = sBody
Next k
End If
Set OutMail = OutApp.CreateItem(0)
On Error Resume Next
With OutMail
.To = sTo
.Subject = ssubject
.body = sBody
.Send
End With
Next i
End Sub
Your problem is occurring because you are testing whether or not this is the first time that the email id has been used and, if it isn't, you are resending the last email you set up.
The End If for your test needs to be moved after the section which sends the email:
Private Sub CommandButton3_Click()
Dim OutApp As Object
Dim OutMail As Object
Set OutApp = CreateObject("Outlook.Application")
With Application
.EnableEvents = False
.ScreenUpdating = False
End With
Dim wSht As Worksheet
Dim LastRow As Long, lCuenta As Long
Dim i As Integer, k As Integer
Dim sTo As String, sSbject As String, sBody As String
Set wSht = ActiveSheet
LastRow = Cells(Rows.Count, 1).End(xlUp).Row
For i = 6 To LastRow
lCuenta = Application.WorksheetFunction.CountIf(Range("W6:W" & i), Range("W" & i))
If lCuenta = 1 Then
ssubject = "PD Call Back"
sTo = wSht.Cells(i, 1)
sBody = wSht.Cells(i, 24)
For k = i To LastRow
If wSht.Cells(i, 1).Value = wSht.Cells(k + 1, 1).Value Then
sBody = sBody & vbNewLine & wSht.Cells(k + 1, 24).Value
End If
wSht.Cells(i, 25) = sBody
Next k
'End If '<-- Move this
Set OutMail = OutApp.CreateItem(0)
On Error Resume Next
With OutMail
.To = sTo
.Subject = ssubject
.body = sBody
.Send
End With
End If '<-- To here
Next i
End Sub
Hi I have all my clients email address in row A on my excel sheet Named "Email". I have created the code below so that a box pops up when I press a bottom on the sheet and I can type the subject, and a few body lines. I want to be able to send the same message to all my client. IE for promotion or if we had to shut the office unexpectedly ect. Can any one help please?
Private Sub CommandButtonSend_Click()
Dim Email_Subject, Email_Send_From, Email_Body1, Email_Body2, Email_Sig, Email_Twitter As String
Dim Mail_Object, Mail_Single As Variant
Dim emailrange As Range, cell As Range
Dim Email_Send_To As String
Set emailrange = Worksheets("Email").Range("A2:A4")
For Each cell In emailrange
Email_Send_To = Email_Send_To & "j" & cell.Value
Next
Email_Send_To = Mid(Email_Send_To, 2)
On Error Resume Next
Email_Subject = UserFormTemplate.TextBoxSubject.Text
Email_Send_From = "shaunha#coversure.co.uk"
Email_Body1 = UserFormTemplate.TextBoxLine1.Text
Email_Body2 = UserFormTemplate.TextBoxLine2.Text
Email_Sig = UserFormTemplate.TextBoxSig.Text
Email_Twitter = UserFormTemplate.TextBoxTwitter.Text
On Error GoTo debugs
Set Mail_Object = CreateObject("Outlook.Application")
Set Mail_Single = Mail_Object.CreateItem(0)
With Mail_Single
.Subject = Email_Subject
.To = Email_Send_To
.cc = Email_Cc
.BCC = Email_Bcc
.Body = Email_Body1 & vbNewLine & Email_Body2 & vbNewLine & vbNewLine & "Shaun Harrison Insurance Consultant" & vbNewLine & "Tel: 0800 308 1022 / shaunha#coversure.co.uk" & vbNewLine & vbNewLine & Email_Twitter
.send
End With
debugs:
If Err.Description <> "" Then MsgBox Err.Description
End
End Sub
Sub SendySend()
With ActiveSheet
EndRow = .Cells(.Rows.Count, "A").End(xlUp).Row
End With
RowCount = 4
For XCount = 4 To EndRow
Dim olApp As Outlook.Application
Set olApp = CreateObject("Outlook.application")
Dim olmail As Outlook.MailItem
Set olmail = olApp.CreateItem(olMailItem)
If Range("D" & RowCount).Value = "Yes" Then
olmail.To = Range("A" & RowCount).Value
olmail.Subject = Range("B" & RowCount).Value
olmail.Body = Range("C" & RowCount).Value
olmail.Send
Else
DontSend = 1 'This Doesn't do anything at all, it's just for clarity
End If
RowCount = RowCount + 1
Next
End Sub