Sending individual personolized emails through VBA

warfo09

New Member
Joined
Feb 15, 2016
Messages
6
Hi folks,

I'm trying to send out individual emails, I got the code working for me, but now need slight alterations, which I gave up trying to implement this weekend...can't figure it out.

My VBA code loops through Column "I" with people's names and creates a list of emails. In email body there's a list of rows for each person to be included in the body of the email, from columns B, C, G, I. Pretty straightforward, however I encounter an issue with the latter. It only takes the first row for each person, i.e. doesn't loop through the list to get all of the rows for one individual recipient.

Here's the data to give you an idea
Untitled.png
:

Basically, my code DOES generate individual emails, i.e. one for John Smith and one for Antoine Jones. But for some reason in the email body it only takes the first row for their name and ignores the rest. I.e. it doesn't loop through all of the rows for all of the names. Any idea why? And the second issue, how do I make it start at row 3? It currently thinks Row2 with headings is the start of my data....here's my code:
Code:
Sub SendEmail3()

Dim OutlookApp
Dim MItem
Dim cell As Range
Dim Subj As String
Dim EmailAddr As String
Dim PriorRecipients As String
Dim Msg As String
Dim Projects As String


'Create Outlook object
Set OutlookApp = CreateObject("Outlook.Application")
'Loop through each person and send email if they haven't already received one.
For Each cell In Columns("I").Cells.SpecialCells(xlCellTypeVisible)
     If cell.Value <> "" Then
        'first build email address
        EmailAddr = LCase$(Replace(cell.Value, " ", ".")) & "@company.com"
        Projects = vbCrLf & "Document: " & Cells(cell.Row, "B").Value & "; " & Cells(cell.Row, "C").Value & "; " & "Rev " & Cells(cell.Row, "G").Value & "; " & Cells(cell.Row, "I").Value
        'then check if it is in Recipient List build, if not, add it, otherwise ignore
         'If the recipient has already received an email, skip

         If InStr(1, PriorRecipients, EmailAddr) <> 0 Then
             GoTo NextRecipient
         End If

         PriorRecipients = PriorRecipients & ";" & EmailAddr
         'Create Mail Item and view before sending
         Set MItem = OutlookApp.CreateItem(olMailItem)

Msg = "You have the following outstanding documents to be reviewed." & vbCrLf & "Full list of documents to be reviewed below:" & vbCrLf & vbCrLf & Projects
Subj = "Outstanding Documents to be Reviewed"
         With MItem
              .To = EmailAddr 'single email address
              .Subject = Subj
              .Body = Msg
              .display
              'This will show for EVERY person.  Skip this and change to .send to just send without showing the email.
         End With
      End If
NextRecipient:
 Next

End Sub

Appreciate your help!
 

Excel Facts

Which came first: VisiCalc or Lotus 1-2-3?
Dan Bricklin and Bob Frankston debuted VisiCalc in 1979 as a Visible Calculator. Lotus 1-2-3 debuted in the early 1980's, from Mitch Kapor.
You have to add Projects back to itself each loop.
Code:
        Projects = Projects & vbCrLf & "Document: " & Cells(cell.Row, "B").Value & "; " & _
            Cells(cell.Row, "C").Value & "; " & "Rev " & Cells(cell.Row, "G").Value & _
            "; " & Cells(cell.Row, "I").Value
 
Upvote 0
You have to add Projects back to itself each loop.
Code:
        Projects = Projects & vbCrLf & "Document: " & Cells(cell.Row, "B").Value & "; " & _
            Cells(cell.Row, "C").Value & "; " & "Rev " & Cells(cell.Row, "G").Value & _
            "; " & Cells(cell.Row, "I").Value

Thanks for your suggestion Tinbendr.

That works, but the Projects are being split incorrectly between the two emails.
I might be mistaken, but this can be due to this part of the code:

Code:
  If InStr(1, PriorRecipients, EmailAddr) <> 0 Then
             GoTo NextRecipient
         End If
I.e. as soon as it sees the first email being used twice, it dumps the rest of projects to the next email body. This is what I get in the end:

Untitled.jpg


Any suggestions how to approach this? Thanks!
 
Upvote 0
Can you sort by email name, then apply filter?

Else this code is going to get complicated.
 
Upvote 0
Can you sort by email name, then apply filter?

Else this code is going to get complicated.

Thing is, I have quite a few names, so I'd rather have many Outlook windows than filter manually...I feel like I'm missing something obvious though... :mad:
 
Upvote 0
The way the code is written, anytime the recipient is different, a new email is generated. The only way to prevent this, in it's current state, is to make all the emails group together.

Like I said earlier, I can make it do that, but a lot of this code will have to go away.
 
Upvote 0
The way the code is written, anytime the recipient is different, a new email is generated. The only way to prevent this, in it's current state, is to make all the emails group together.

Like I said earlier, I can make it do that, but a lot of this code will have to go away.

Well, as long as it works... Would you be able to look into this if it doesn't take too much of your time? Appreciate your help...
 
Upvote 0
OK, give this a go.
Code:
Option Explicit

Sub SendEmail3()
Dim OutlookApp As Object
Dim MItem As Object
Dim aCell As Range
Dim Subj As String
Dim EmailAddr As String
Dim Msg As String
Dim Projects As String
Dim A As Long
Dim Unique As New Collection
    
'Loop through each person and send email if they haven't already received one.
For Each aCell In Columns("I").Cells.SpecialCells(xlCellTypeVisible)
     If aCell.Value <> "Name" Then
        On Error Resume Next
        Unique.Add CStr(aCell), CStr(aCell)
        On Error GoTo 0
     End If
Next

For A = 1 To Unique.Count
    For Each aCell In Columns("I").Cells.SpecialCells(xlCellTypeVisible)
         If aCell.Value = Unique(A) Then
            'first build email address
            EmailAddr = LCase$(Replace(aCell.Value, " ", ".")) & "@company.com"
            Projects = Projects & vbCrLf & "Document: " & Cells(aCell.Row, "B").Value & "; " & _
                Cells(aCell.Row, "C").Value & "; " & "Rev " & Cells(aCell.Row, "G").Value & _
                "; " & Cells(aCell.Row, "I").Value
        End If
    Next
            Debug.Print Projects
        'Create Outlook object
        Set OutlookApp = CreateObject("Outlook.Application")
         'Create Mail Item and view before sending
         Set MItem = OutlookApp.CreateItem(0) 'olMailItem
        
        Msg = "You have the following outstanding documents to be reviewed." & vbCrLf & _
            "Full list of documents to be reviewed below:" & vbCrLf & vbCrLf & Projects
        Subj = "Outstanding Documents to be Reviewed"
         With MItem
              .To = EmailAddr 'single email address
              .Subject = Subj
              .Body = Msg
              .display
              'This will show for EVERY person.  Skip this and change to .send to just send without showing the email.
         End With
      
NextRecipient:
Next
Set MItem = Nothing
Set OutlookApp = Nothing
End Sub
 
Upvote 0
OK, give this a go.
Code:
Option Explicit

Sub SendEmail3()
Dim OutlookApp As Object
Dim MItem As Object
Dim aCell As Range
Dim Subj As String
Dim EmailAddr As String
Dim Msg As String
Dim Projects As String
Dim A As Long
Dim Unique As New Collection
    
'Loop through each person and send email if they haven't already received one.
For Each aCell In Columns("I").Cells.SpecialCells(xlCellTypeVisible)
     If aCell.Value <> "Name" Then
        On Error Resume Next
        Unique.Add CStr(aCell), CStr(aCell)
        On Error GoTo 0
     End If
Next

For A = 1 To Unique.Count
    For Each aCell In Columns("I").Cells.SpecialCells(xlCellTypeVisible)
         If aCell.Value = Unique(A) Then
            'first build email address
            EmailAddr = LCase$(Replace(aCell.Value, " ", ".")) & "@company.com"
            Projects = Projects & vbCrLf & "Document: " & Cells(aCell.Row, "B").Value & "; " & _
                Cells(aCell.Row, "C").Value & "; " & "Rev " & Cells(aCell.Row, "G").Value & _
                "; " & Cells(aCell.Row, "I").Value
        End If
    Next
            Debug.Print Projects
        'Create Outlook object
        Set OutlookApp = CreateObject("Outlook.Application")
         'Create Mail Item and view before sending
         Set MItem = OutlookApp.CreateItem(0) 'olMailItem
        
        Msg = "You have the following outstanding documents to be reviewed." & vbCrLf & _
            "Full list of documents to be reviewed below:" & vbCrLf & vbCrLf & Projects
        Subj = "Outstanding Documents to be Reviewed"
         With MItem
              .To = EmailAddr 'single email address
              .Subject = Subj
              .Body = Msg
              .display
              'This will show for EVERY person.  Skip this and change to .send to just send without showing the email.
         End With
      
NextRecipient:
Next
Set MItem = Nothing
Set OutlookApp = Nothing
End Sub

Thanks David. Haven't tried your solution, but managed to get mine working in the end. Here's the code if anyone needs it. It uses sorting features and based on that sends out individual emails using RangeToHTML (you can find this function online)
Sub Sendemail()
'
' This will create an actionlist email
'
Dim SMARTrng As Range
Dim OPENrng As Range
Dim OutApp As Object
Dim OutMail As Object
Dim SendTo(60) As Variant
Dim EmailAddr(60) As Variant
Dim y_s As String
'Clear all data from cells first
Range("A1:S999").Clear
'Import the list from sharepoint

With Application
.EnableEvents = True
.ScreenUpdating = True
End With

currentsheet = ActiveSheet.Name
currentwindow = ActiveWindow.Caption
Windows(currentwindow).Activate


''sort by reviewer & then sort by company
Rows("1:1").Select
Selection.AutoFilter
ActiveWorkbook.Worksheets("Macro").Sort.SortFields.Clear
ActiveWorkbook.Worksheets("Macro").Sort.SortFields.Add Key:=Range("m2:m999") _
, SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
ActiveWorkbook.Worksheets("Macro").Sort.SortFields.Add Key:=Range("J2:J999") _
, SortOn:=xlSortOnValues, Order:=xlAscending, DataOption:=xlSortNormal
With ActiveWorkbook.Worksheets("Macro").Sort
.SetRange Range("A1:S999")
.Header = xlYes
.MatchCase = False
.Orientation = xlTopToBottom
.SortMethod = xlPinYin
.Apply
End With

'filter for reviewed = no and info only = blank

ActiveSheet.Range("$A$1:$AM$999").AutoFilter Field:=15, Criteria1:="No"
ActiveSheet.Range("$A$1:$AM$999").AutoFilter Field:=16, Criteria1:="="
'get list of emails
n = 0
ActiveSheet.Range("M2").Select

'filter for reviewed = no and info only = blank

If n <> 0 Then Reviewer = ActiveCell.Value
For y = 1 To 2000

ActiveCell.Offset(1, 0).Select
If ActiveCell.Rows.Hidden = False Then
If ActiveCell.Value <> Reviewer Then
SendTo(n) = ActiveCell.Value
Reviewer = ActiveCell.Value
EmailAddr(n) = LCase$(Replace(ActiveCell.Value, " ", ".")) & "@company.com"

If ActiveCell.Value = "" Then Exit For
n = n + 1
End If
End If

Next y

y_s = y



' build HTML table for email

For Z = 0 To n - 1
ActiveSheet.Range("$A$2:$Z$2000").AutoFilter Field:=13, Criteria1:=SendTo(Z)
Set SMARTrng = Sheets(currentsheet).Range("e1:n" + y_s).SpecialCells(xlCellTypeVisible)
smartHTML = RangetoHTML(SMARTrng)

'-----------------------------
' display the email
'-----------------------------

Set OutApp = CreateObject("Outlook.Application")
Set objNamespace = OutApp.GetNamespace("MAPI")
objNamespace.Session.Logon "Outlook", , False, True
Set OutMail = OutApp.CreateItem(0)

With OutMail
.To = EmailAddr(Z)


.CC = ""
.BCC = ""
.Subject = "Documents That Require Review"


.HTMLBody = "You have the following outstanding documents to be reviewed at " _
+ " <a href =XXX> Link to Docs</a> <BR/> <BR/> " _
+ " Please review or delegate. If you have reviewed the document(s) please go to the above link<BR/> <BR/>" _
+ " <BR/> " _
+ smartHTML

If ActiveSheet.Range("t1").Value = True Then
.display
Else
.display
End If

End With

Next Z

With Application
.EnableEvents = True
.ScreenUpdating = True
End With

Set Objapp = Nothing
Set OutMail = Nothing

If ActiveSheet.FilterMode = True Then ActiveSheet.ShowAllData

End Sub
 
Upvote 0
P.S. delete this line

Range("A1:S999").Clear

As I was importing from sharepoint each time and calling the fuction afterwards.
 
Upvote 0

Forum statistics

Threads
1,223,236
Messages
6,170,912
Members
452,366
Latest member
TePunaBloke

We've detected that you are using an adblocker.

We have a great community of people providing Excel help here, but the hosting costs are enormous. You can help keep this site running by allowing ads on MrExcel.com.
Allow Ads at MrExcel

Which adblocker are you using?

Disable AdBlock

Follow these easy steps to disable AdBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the icon in the browser’s toolbar.
2)Click on the "Pause on this site" option.
Go back

Disable AdBlock Plus

Follow these easy steps to disable AdBlock Plus

1)Click on the icon in the browser’s toolbar.
2)Click on the toggle to disable it for "mrexcel.com".
Go back

Disable uBlock Origin

Follow these easy steps to disable uBlock Origin

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back

Disable uBlock

Follow these easy steps to disable uBlock

1)Click on the icon in the browser’s toolbar.
2)Click on the "Power" button.
3)Click on the "Refresh" button.
Go back
Back
Top