Outlook Email Macro - excel

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

Related

Excel - Run-time error 13 in vba macro created

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

Auto send email to multiple recipients

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,";"),";")

Need to send email to multiple reciepent from filter data

I wanted to send email to multiple recipient as per their fund code. for eg. in given image I want email for QR fund in column A to be sent out to B2,B3 and B4 in same email and subject line should be "C2" for next I want email for RTIO fund in column A to be sent out to B5, B7 and B8 in same email and subject line should be "C5" and so on
Sub SendMultipleEmails()
Dim Mail_Object, OutApp As Variant
With ActiveSheet
lastrow = .Cells(.Rows.Count, "b").End(xlUp).Row
End With
For i = 2 To lastrow
Set Mail_Object = CreateObject("Outlook.Application")
Set OutApp = Mail_Object.CreateItem(0)
With OutApp
.Subject = "Your subject here"
.Body = "Your message here"
.To = Cells(i, 2).Value
.dISPLAY
End With
I am not able to apply filter condition and get multiple email recipient in one email
Try this code:
Sub SendMultipleEmailsaa()
Dim Mail_Object, OutApp As Object
Dim ws As Worksheet: Set ws = ActiveSheet
Dim arr() As Variant
LastRow = ws.Cells(ws.Rows.Count, "b").End(xlUp).row
arr = ws.Range("A2:A" & LastRow)
Set Mail_Object = CreateObject("Outlook.Application")
first = 2
For i = LBound(arr) To UBound(arr)
If i = UBound(arr) Then GoTo YO
If arr(i + 1, 1) = arr(i, 1) Then
first = WorksheetFunction.Min(first, i + 1)
Else
YO:
Set OutApp = Mail_Object.CreateItem(0)
With OutApp
.Subject = ws.Range("C" & i + 1).Value
.Body = "Your message here"
.Display
.To = ws.Range("A" & i + 1).Value
For j = first To i
.Recipients.Add ws.Range("A" & j).Value
Next
first = i + 2
End With
End If
Next
End Sub
To automatically sort add this code below the calculation on LastRow in above code:
ws.Sort.SortFields.Clear
ws.Sort.SortFields.Add2 Key:=ws.Range("A2:A" & LastRow), SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
With ws.Sort
.SetRange ws.UsedRange
.Header = False
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With
Another Update:
Dim bc As String
With OutApp
.Subject = ws.Range("C" & i + 1).Value
.Body = "Your message here"
.Display
bc = ws.Range("A" & i + 1).Value
For j = first To i
bc = bc & ";" & ws.Range("A" & j).Value
Next
.BCC = bc
first = i + 2
End With
Here is my solution:
Option Explicit
Public Sub Main()
Dim rngSource As Range: Set rngSource = ExpandRange(ThisWorkbook.Worksheets("Sheet1").Range("A2"))
ReadDataAndSendAllMail rngSource
End Sub
Public Function ExpandRange(rngTopLeftCell As Range) As Range
With rngTopLeftCell.Worksheet
Set ExpandRange = rngTopLeftCell.Resize( _
.Cells(.Rows.Count, rngTopLeftCell.Column).End(xlUp).Row - rngTopLeftCell.Row + 1, _
.Cells(rngTopLeftCell.Row, .Columns.Count).End(xlToLeft).Column - rngTopLeftCell.Column + 1)
End With
End Function
Public Sub ReadDataAndSendAllMail(rngSource As Range)
Dim dctData As Dictionary: Set dctData = ReadData(rngSource)
SendAllMail dctData
End Sub
Public Function ReadData(rngSource As Range) As Dictionary
Dim dctResult As Dictionary: Set dctResult = New Dictionary
Dim rngRecord As Range: For Each rngRecord In rngSource.Rows
Dim dctRecord As Dictionary: Set dctRecord = New Dictionary
dctRecord.Add "Fund", rngRecord.Cells(1, 1).Value
dctRecord.Add "Email", rngRecord.Cells(1, 2).Value
dctRecord.Add "Subject", rngRecord.Cells(1, 3).Value
dctRecord.Add "Attachment", rngRecord.Cells(1, 4).Value
If Not dctResult.Exists(dctRecord("Fund")) Then
dctResult.Add dctRecord("Fund"), New Collection
End If
dctResult(dctRecord("Fund")).Add dctRecord
Next rngRecord
Set ReadData = dctResult
End Function
Public Sub SendAllMail(dctData As Dictionary)
Const cstrEmailDelimiter As String = "; " ' Note: Observe which delimiter your local version of Outlook uses and replace this value with it
Dim moaOutlook As Outlook.Application: Set moaOutlook = New Outlook.Application
Dim varFund As Variant: For Each varFund In dctData.Keys
Dim strFund As String: strFund = vbNullString
Dim strTo As String: strTo = vbNullString
Dim strSubject As String: strSubject = vbNullString
Dim strBody As String: strBody = vbNullString
Dim strAttachmentPath As String: strAttachmentPath = vbNullString
Dim dctRecord As Dictionary: For Each dctRecord In dctData(varFund)
strFund = dctRecord("Fund")
strTo = strTo & cstrEmailDelimiter & dctRecord("Email")
strSubject = dctRecord("Subject")
strBody = vbNullString ' Note: Replace vbNullString with some text for the message body
strAttachmentPath = dctRecord("Attachment")
Next dctRecord
strTo = Mid(strTo, Len(cstrEmailDelimiter) + 1)
SendMail moaOutlook, strTo, strSubject, vbNullString, strAttachmentPath
Next varFund
moaOutlook.Quit
End Sub
Public Sub SendMail(moaOutlook As Outlook.Application, strTo As String, strSubject As String, strBody As String, strAttachmentPath As String)
Dim omiMailItem As Outlook.MailItem: Set omiMailItem = moaOutlook.CreateItem(olMailItem)
With omiMailItem
.To = strTo
.Subject = strSubject
.Body = strBody ' Note use .HTMLBody if you want to send an HTML email
.Attachments.Add strAttachmentPath
.display ' Note: If you want to manually press the send button, otherwise comment out this line
' .send ' Note: If you want to automatically send it, uncomment this line
End With
End Sub
I hope the function names make it easier to understand and reuse. I tested it, and worked for me.

Sending Email Based on Cell Value within a Loop

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

How to VBA MAilto all emails in a colum

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

Resources