Merge Cell Range to Outlook - excel

How do I display a range from Excel in Outlook's new email window?
How do I fill the To: and CC: with email addresses from specific cells within the Excel file?
I have the code below which is for object creation. (office 13)
Option Explicit
Private Sub CommandButton1_Click()
On Error GoTo ErrHandler
Dim objOutlook As Object
Set objOutlook = CreateObject("Outlook.Application")
Dim objEmail As Object
Set objEmail = objOutlook.CreateItem(olMailItem)
With objEmail
.to = ""
.Subject = ""
.Body = ""
.Display
End With
Set objEmail = Nothing: Set objOutlook = Nothing
ErrHandler:
'
End Sub

If you have multiple email addresses in a range, for example in "A1:A3", you can create a list and set the .To property equal to this list (same approach for .CC):
Dim ws As Worksheet, rng As Range, sTo As String
Set ws = ThisWorkbook.Worksheets("Email Addresses")
For Each rng In ws.Range("A1:A3")
sTo = sTo & rng & ", " 'creates To: list
Next
sTo = Left(sTo, Len(sTo) - 2) 'removes last ", "
With objEmail
.To = sTo
.subject = ""
.Body = ""
.Display
End With

Just add the cell after the TO: and it will get the value in it. Let say your email address is in B1, the code would look like this:
.To = Cells(1, 2).Value
To add a range, you need to convert it to a string before. You need to add this part before your email part:
Dim myCell As Range, myString As String
For Each myCell In Range("A1:A2") 'Change range to suit your needs
myString = myString & "," & myCell.Value
Next myCell
'Remove extra comma
myString = Right(myString, Len(myString) - 1)
With this piece of code, you'll convert your range to a string with comma between each cells. You can change "," with vbLf to get the next cell on a different line instead of a comma.
Here is an example of code with the range as a string:
.Body = "Hi " & Cells(1, 3).Value & "," & vbLf & vbLf _
& "Here is the main text of my email" & vbLf & myString & vbLf & vbLf_
& Application.UserName & vbLf & vbLf
In this example, it use the value in C1 as the name of the person you're writing to, your predefined text and the name of the user at the end.

Related

How to keep the hyperlinks, in table column, clickable when sending to body of mail?

I am trying to send an email via Outlook using VBA.
I have a column filled with hyperlinks. When the email is constructed, the hyperlinks turns into plain text and are not clickable.
I reference the column using Cells(row_num,1) because all the hyperlinks are unique.
How to make them show up as hyperlinks?
Sub SendEmail()
Dim olook As Outlook.Application
Dim omailitem As Outlook.MailItem
Dim i As Byte, row_num As Byte
row_num = 2
Set olook = New Outlook.Application
For i = 1 To 15
Set omailitem = olook.CreateItem(0)
With omailitem
.To = Sheets(1).Cells(row_num, 2)
.Subject = "Tool Notification"
.Body = "Hello!" & vbNewLine & vbNewLine & _
"Below are the link(s) to the task(s) that you have due on: " & _
Cells(row_num, 4).Value & _
vbNewLine & vbNewLine & "Link: " & Cells(row_num, 1).Value & _
vbNewLine & vbNewLine & "Thank you," & _
vbNewLine & vbNewLine & "Tool"
.Display
End With
row_num = row_num + 1
Next
End Sub
Sample Data
https://i.stack.imgur.com/m9Stx.png
Check the code's comments and adjust it to fit your needs.
This should be pasted in a standard module.
EDIT: Adjusted to accumulate links by sender
Code:
Option Explicit
Sub SendEmail()
Dim olApp As Outlook.Application
Dim olMail As Outlook.MailItem
Dim targetSheet As Worksheet
Dim targetRange As Range
Dim cell As Range
Dim lastRow As Long
Dim recipientAddr As String
Dim bodyContent As String
Dim duedateFormat As String
Dim linkFormat As String
' Set reference to target Sheet (replace 1 with the sheet's name or codename)
Set targetSheet = ThisWorkbook.Worksheets(1)
' Find last cell in column b
lastRow = targetSheet.Cells(targetSheet.Rows.Count, 2).End(xlUp).Row
' Set target range
Set targetRange = targetSheet.Range("B2:B" & lastRow)
' Start new outlook instance
Set olApp = New Outlook.Application
' Loop through each cell in column B
For Each cell In targetRange.Cells
' If cell has data
If cell.Value <> vbNullString Then
' Check if is the same recipient as next
If cell.Value = cell.Offset(1, 0).Value Then
linkFormat = linkFormat & "" & cell.Offset(0, -1) & "<br>"
Else
linkFormat = linkFormat & "" & cell.Offset(0, -1) & ""
' Collect email data from cells
recipientAddr = cell.Value
duedateFormat = Format(cell.Offset(0, 2).Value, "mm-dd-yyyy")
' Build the link string
bodyContent = "Hello!<br><br>" & _
"Below are the link(s) to the task(s) that you have due on: " & duedateFormat & "<br><br>" & _
"Link(s): <br>" & _
linkFormat & "<br><br>" & _
"Thank you,<br><br>" & _
"Tool"
' Create the mail item and display it
Set olMail = olApp.CreateItem(olMailItem)
With olMail
.To = cell.Value
.Subject = "Tool Notification"
.HTMLBody = bodyContent
.Display
End With
' Reset the link
linkFormat = vbNullString
End If
End If
Next cell
End Sub
Let me know if it works

Impossible Excel-VBA Email Loop

If someone could help me from going insane, my mother would appreciate it.
I have a long list of email addresses (many repeats) with associated Audit Locations. Basically I need to create one email for each email address and populate said email body with a list of all the associated Audit Locations.
e.g.
Column One (Email Address) | Column 2 (Audit Location)
Yoda1#lightside.org | Coruscant
Yoda1#lightside.org | Death Star
Yoda1#lightside.org | Tatooine
Vader#Darkside.org | Death Star
Vader#Darkside.org | Coruscant
Jarjar#terrible.org | Yavin
So far I have created a CommandButton Controlled vba that takes Column One and makes it unique in a new worksheet.
Then I have another sub that creates an email for each unique email address. But I am stuck on the "If...Then" statement. Essentially, I want to add the information in Column 2 (Audit Location) if the Recipient of the email is the email address in Column One and then continue to append to the email body until the email address no longer equals the recipient email address. Any guidance would be huge.
Private Sub CommandButton1_Click()
Call MakeUnique
Call EmailOut
End Sub
Sub MakeUnique()
Dim vaData As Variant
Dim colUnique As Collection
Dim aOutput() As Variant
Dim i As Long
'Put the data in an array
vaData = Sheet1.Range("A:A").Value
'Create a new collection
Set colUnique = New Collection
'Loop through the data
For i = LBound(vaData, 1) To UBound(vaData, 1)
'Collections can't have duplicate keys, so try to
'add each item to the collection ignoring errors.
'Only unique items will be added
On Error Resume Next
colUnique.Add vaData(i, 1), CStr(vaData(i, 1))
On Error GoTo 0
Next i
'size an array to write out to the sheet
ReDim aOutput(1 To colUnique.Count, 1 To 1)
'Loop through the collection and fill the output array
For i = 1 To colUnique.Count
aOutput(i, 1) = colUnique.Item(i)
Next i
'Write the unique values to column B
Sheets.Add.Name = "Unique"
ActiveSheet.Range("A1").Resize(UBound(aOutput, 1), UBound(aOutput, 2)).Value = aOutput
End Sub
Sub EmailOut()
Dim xOutApp As Object
Dim xOutMail As Object
Dim xMailBody As String
On Error Resume Next
Dim cell As Range
For Each cell In Worksheets("Unique").Columns("a").Cells.SpecialCells(xlCellTypeConstants)
recip = cell.Value
Set xOutApp = CreateObject("Outlook.Application")
Set xOutMail = xOutApp.CreateItem(0)
For Each org In Columns("b").Cells.SpecialCells(xlCellTypeConstants)
If org.Value Like recip Then
xMailBody = "Body content" & vbNewLine & vbNewLine & _
"This is line 1" & " " & cell.Offset(0, 3).Value & vbNewLine & _
[B5] & vbNewLine & _
"This is line 2"
End If
Next org
On Error Resume Next
With xOutMail
.To = recip
.CC = ""
.BCC = ""
.Subject = cell.Offset(0, 2).Value & " " & cell.Offset(0, 3).Value & " " & "Remittance Advice"
.Body = xMailBody
.Display 'or use .Send
End With
On Error GoTo 0
Set xOutMail = Nothing
Set xOutApp = Nothing
Next
End Sub
Based on your example I quickly wrote the following:
Option Explicit
Public Sub SendEmails()
Dim dictEmailData As Object
Dim CurrentWorkBook As Workbook
Dim WrkSht As Worksheet
Dim rngToLookUp As Range
Dim lngLastRow As Long, i As Long
Dim arryEmailData As Variant
Dim objOutlookApp As Object, objOutlookEmail As Object
Dim varKey As Variant
Application.ScreenUpdating = False
Set CurrentWorkBook = Workbooks("SomeWBName")
Set WrkSht = CurrentWorkBook.Worksheets("SomeWSName")
lngLastRow = WrkSht.Cells(WrkSht.Rows.Count, "A").End(xlUp).Row 'Find last row with data
Set rngToLookUp = WrkSht.Range("A2:B" & lngLastRow) 'set range for last row of data
arryEmailData = rngToLookUp.Value2 'Get the email data from the sheet into an array
Set dictEmailData = CreateObject("Scripting.Dictionary") 'set the dicitonary object
On Error GoTo CleanFail
For i = LBound(arryEmailData, 1) To UBound(arryEmailData, 1)
varKey = UCase(Trim(arryEmailData(i, 1)))
If Not dictEmailData.Exists(varKey) Then
dictEmailData(varKey) = vbNewLine & vbNewLine & Trim(arryEmailData(i, 2))
Else
dictEmailData(varKey) = dictEmailData(varKey) & vbNewLine & Trim(arryEmailData(i, 2))
End If
varKey = Empty
Next i
'for each unique key in the dicitonary
'get the corresponding item
'created in the loop above
Set objOutlookApp = CreateObject("Outlook.Application") 'set the outlook object
Dim Msg As String, MailBody As String
For Each varKey In dictEmailData.Keys
Msg = dictEmailData.Item(varKey)
Set objOutlookEmail = objOutlookApp.CreateItem(0)
MailBody = "Dear Colleague," & Msg
With objOutlookEmail
.To = varKey
.Subject = "Remittance Advice"
.Body = MailBody
.Send
End With
Set objOutlookEmail = Nothing
Msg = Empty: MailBody = Empty
Next
MsgBox "All Emails have been sent", vbInformation
CleanExit:
Set objOutlookApp = Nothing
Application.ScreenUpdating = True
Exit Sub
CleanFail:
Resume CleanExit
End Sub
Add the first occurrence of a varKey = email address to the dictionary dictEmailData along with its corresponding item dictEmailData(varKey) = Email body. On the next occurrence of the email address, append to the Email body. Once the dictionary is built, loop through it and send the emails
Printing to the immediate window yields:

Change loop from every cell to particular range in Excel VBA

I have the following piece of code which sends emails in bulk.
Sub Sengrd_Files()
Dim OutApp As Object
Dim OutMail As Object
Dim sh As Worksheet
Dim cell As Range
Dim FileCell As Range
Dim rng As Range
para2 = ""
para3 = ""
para232 = Range("AA2").Value
With Application
.EnableEvents = False
.ScreenUpdating = True
End With
Set sh = Sheets("Sheet1")
Set OutApp = CreateObject("Outlook.Application")
For Each cell In sh.Columns("B").Cells.SpecialCells(xlCellTypeConstants)
'Enter the path/file names in the C:Z column in each row
Set rng = sh.Cells(cell.Row, 1).Range("C1:Z1")
If cell.Value Like "?*#?*.?*" And _
Application.WorksheetFunction.CountA(rng) > 0 Then
Set OutMail = OutApp.CreateItem(0)
With OutMail
.to = cell.Value
.Subject = "Circle Profitability Report for the period ended 30-NOV-2017"
.Body = "Dear Sir/Madam," _
& vbNewLine _
& para232 & vbNewLine _
& vbNewLine & para2 & vbNewLine _
& Remark & vbNewLine & vbNewLine _
& para3 & vbNewLine & vbNewLine
For Each FileCell In rng.SpecialCells(xlCellTypeConstants)
If Trim(FileCell) <> "" Then
If Dir(FileCell.Value) <> "" Then
.Attachments.Add FileCell.Value
End If
End If
Next FileCell
.Send 'Or use .Display
End With
Set OutMail = Nothing
End If
Next cell
Set OutApp = Nothing
With Application
.EnableEvents = True
.ScreenUpdating = True
End With
End Sub
7 different mails will be sent to different people mentioned in Column B with Attachment defined in Col C.
The Macro by default sends mails for ALL line items probably because of this line in code
**For Each cell In sh.Columns("B").Cells.SpecialCells(xlCellTypeConstants)**
I cannot define a variable i and change the above line to
**For Each i =1 to 5 sh.Columns("B").Cells.SpecialCells(xlCellTypeConstants)**
due to syntax error. Can anyone help me in syntax in replacing "For each cell in" to a finite range.
This is how to make the bulk-mail-sender send only to a given range (in this case B2 - B5):
For Each cell In sh.Range("B2:B5")
And do not forget - spam is bad.

Making unambiguous concatenate when retrieving info for email

The aim is to check individual worksheets for a list of dates in a range, and then send an email listing these dates to an email address located in the sheet.
The current code concatenates the dates in the current sheet as well as the dates on the previous sheet, instead of just the dates found on this sheet.
I'm struggling to make it uni-vocal, tried putting "ws." before each aCell instruction but get compile error.
Sub Mail_Outlook()
Dim ws As Worksheet
Dim wsName As Variant
Dim OutApp As Object
Dim OutMail As Object
Dim cell As Range
Dim strbody As String
Dim string1 As String
Dim aCell As Range
Dim i As Integer
i = 0
For Each wsName In Array("sheet1", "sheet2", "sheet3")
Set ws = Worksheets(wsName)
'retrieve all missing dates
For Each aCell In ws.Range("Aa1:Aa1000")
If aCell.Value <> "" Then
i = i + 1
If i <> 1 Then
string1 = string1 & ", " & aCell.Value
Else
string1 = aCell.Value
End If
End If
Next
'send email
Set OutApp = CreateObject("Outlook.Application")
Set OutMail = OutApp.CreateItem(0)
strbody = "Good day " & ws.Range("E3").Cells & vbNewLine & vbNewLine & _
"" & vbNewLine & vbNewLine & _
"" & vbNewLine & vbNewLine & _
string1 & vbNewLine & vbNewLine & vbNewLine & vbNewLine & _
"(This is an automated message)" & vbNewLine & vbNewLine & _
"Best regards" & vbNewLine & vbNewLine & _
On Error Resume Next
With OutMail
.To = ws.Range("E5").Text
.CC = ""
.BCC = ""
.Subject = ""
.Body = strbody
'You can add a file like this
'.Attachments.Add ("C:\test.txt")
.Display 'or use .Send
End With
On Error GoTo 0
Set OutMail = Nothing
Set OutApp = Nothing
Next
End Sub
From the OP's comments:
code as is produces no errors, but e.g. the second email contains the string for the first sheet and second sheet, rather than just the second sheet.
Zero the string before going into the second iteration of the loop.
For Each wsName In Array("sheet1", "sheet2", "sheet3")
Set ws = Worksheets(wsName)
string1 = vbNullString 'reset string1 to a zero-length string for each ws
'retrieve all missing dates
For Each aCell In ws.Range("Aa1:Aa1000")
'all the rest of the concatenation code
next aCell
'all the rest of the email code
Next wsName

I have a list of email addresses in excel that i need to send emails to. The subject and body are in cells besides the email address

As mentioned in the subject of this post, I am attempting to send emails automatically by running a macro so that if cell J2 has the words "Send Reminder" in it, then the email address in cell K2 should be sent an email with the subject title in cell L2 and Body in Cell M. I have a list of emails ranging from cells K2:K59
Currently I have the following code:
Sub SendEm()
Dim i As Integer, Mail_Object, Email_Subject, o As Variant, lr As Long
lr = Cells(Rows.Count, "K").End(xlUp).Row
Set Mail_Object = CreateObject("Outlook.Application")
For i = 2 To lr
With Mail_Object.CreateItem(o)
.Subject = Range("L2").Value
.To = Range("K" & i).Value
.Body = Range("M2").Value
.Send
End With
Next i
MsgBox "E-mail successfully sent", 64
Application.DisplayAlerts = False
Set Mail_Object = Nothing
End Sub
I already have outlook open with references for Microsoft Outlook 14.0 Object Library selected amongst others, and I get an error saying " Run-time error '287' Application-definer or object-defined error, if i try to debug it, it highlights .Send in my code.
Can anyone help point out what I am doing wrong? I have tried various types of code to send emails based on different youtube videos etc. but seem to run into this error each time!
Thanks for your help ahead of time!
Edit1: I updated the code to the following based on suggestions and now a different issue:
Private Sub CommandButton21_Click()
'~~> Excel Objects/Variables
Dim ws As Worksheet
Dim lRow As Long, i As Long
'~~> Outlook Objects/Variables
Dim OutApp As Object
Dim OutMail As Object
Dim emailRange As Range, cl As Range
Dim sTo As String
Dim subjectRange As Range, c2 As Range
Dim sSubject As String
Dim bodyRange As Range, c3 As Range
Dim sBody As String
'~~> Set your worksheet here
Set ws = ThisWorkbook.Sheets("Sheet11")
'~~> Open Outlook
Set OutApp = CreateObject("Outlook.Application")
With ws
'~~> Get last row from Col J as that is what we
'~~> are going to check for the condition
lRow = .Range("J" & .Rows.Count).End(xlUp).Row
'~~> Loop through the rows
For i = 2 To lRow
If .Range("J" & i).Value = "Send Reminder" Then
'~~> Create new email
Set emailRange = Worksheets("Sheet11").Range("K2:K59")
For Each cl In emailRange
sTo = sTo & ";" & cl.Value
Next
sTo = Mid(sTo, 2)
Set subjectRange = Worksheets("Sheet11").Range("L2:L59")
For Each c2 In subjectRange
sSubject = sSubject & ";" & c2.Value
Next
sSubject = Mid(sSubject, 2)
Set bodyRange = Worksheets("Sheet11").Range("M2:M59")
For Each c3 In bodyRange
sBody = sBody & ":" & c3.Value
Next
sBody = Mid(sBody, 2)
Set OutMail = OutApp.CreateItem(0)
'On Error Resume Next
With OutMail
'~~> Customize your email
.To = ""
.CC = sTo
.BCC = ""
.Subject = "typed subject1" & sSubject
.Body = ""
.Display '<~~ Change to .Send to actually send it
End With
End If
Next i
End With
End Sub
This code opens up multiple windows in outlook with all the emails listed in K2:K59. For example, if three cells in J2:J59 have send reminder, i open 3 email windows with all the emails listed in the cc box, instead of either multiple windows with individual emails or one window with all the emails. I think I have to close the loop somehow but am not certain how! Thanks for your help.
Mail_Object.CreateItem(o)
Shouldn't that be
Mail_Object.CreateItem(0)
0 and not o
In the below code, you are not required to set a reference to MS Outlook Object Library. I am using Late Binding with MS Outlook.
Try this (Untested)
I have commented the code so you shall not have a problem understanding the code but if you do then simply post back :)
Option Explicit
Sub Sample()
'~~> Excel Objects/Variables
Dim ws As Worksheet
Dim lRow As Long, i As Long
'~~> Outlook Objects/Variables
Dim OutApp As Object
Dim OutMail As Object
'~~> Set your worksheet here
Set ws = ThisWorkbook.Sheets("Sheet1")
'~~> Open Outlook
Set OutApp = CreateObject("Outlook.Application")
With ws
'~~> Get last row from Col J as that is what we
'~~> are going to check for the condition
lRow = .Range("J" & .Rows.Count).End(xlUp).Row
'~~> Loop through the rows
For i = 2 To lRow
If .Range("J" & i).Value = "Send Reminder" Then
'~~> Create new email
Set OutMail = OutApp.CreateItem(0)
With OutMail
'~~> Customize your email
.To = ws.Range("K" & i).Value
.Subject = ws.Range("L" & i).Value
.Body = ws.Range("M" & i).Value
.Display '<~~ Change to .Send to actually send it
End With
End If
Next i
End With
End Sub
Since you have Outlook open you do not have to do anything complicated.
Set Mail_Object = GetObject(, "Outlook.Application")
I did something similar yesterday, here is the code I used, hope it helps you out.
Sub EmailCopy()
Dim oApp, oMail As Object, X As Long, MyBody As String
Application.ScreenUpdating = False
On Error Resume Next
Set oApp = CreateObject("Outlook.Application")
For X = 2 To Range("A" & Rows.Count).End(xlUp).Row
MyBody = Replace(Join(Application.Transpose(Range("E5:E" & Range("D" & Rows.Count).End(xlUp).Row - 1).Value), vbLf & vbLf), "<FirstName>", Range("B" & X).Text)
MyBody = MyBody & vbLf & vbLf & Join(Application.Transpose(Range("E" & Range("D" & Rows.Count).End(xlUp).Row & ":E" & Range("E" & Rows.Count).End(xlUp).Row)), vbLf)
Set oMail = oApp.CreateItem(0)
With oMail
.To = Range("A" & X).Text
.cc = Range("E1").Text
.Subject = Range("E2").Text
.Body = MyBody
.Attachments.Add Range("E3").Text
.Display
If UCase(Range("E4").Text) = "SEND" Then
.Send
ElseIf UCase(Range("E4").Text) = "DRAFT" Then
.Save
.Close False
Else
MsgBox "You need to choose Draft or Send in cell E4"
End
End If
End With
Application.ScreenUpdating = True
Set oMail = Nothing
Next
Set oApp = Nothing
End Sub
Recipients go in Column A and First Name goes in column B, Any CC's go in E1, Subject goes in E2, Any attachment links go in E3, E4 is either Draft or Send to create a draft or do a send.
Then the message body goes in E5 down as far as you want, each line will be separated by a double return. Anywhere you use FirstName wrapped in greater than and less than signs the code will replace it with the person's First Name from column B.
Straight after that put the signature you want and put "Signature" in column D next to the start of it, this will be separated by single returns.

Resources