Reply to selected Outlook emails using Excel VBA - excel

Using Excel VBA, I want to reply to emails which I selected/highlighted inside the Outlook application.
There are different email messages and subject lines based on the order which I selected the email messages.
There are replies to the wrong email. It should reply to those which I highlighted in Outlook.
For example when I selected three emails there are instances that two replied correctly but the other one replied to an email which I did not highlight.
Sub SendEmail()
Dim OutlookApp As Object
Dim OutlookMail As Object
i = 1
Do While Not IsEmpty(Cells(i + 1, 4))
Set OutlookApp = CreateObject("Outlook.Application")
Set OutlookMail = OutlookApp.ActiveExplorer.Selection.Item(i)
Dim OutlookConversation As Object
Set OutlookConversation = OutlookMail.GetConversation
Dim OutlookTable As Object
Set OutlookTable = OutlookConversation.GetTable
Dim OutlookAr As Variant
OutlookAr = OutlookTable.GetArray(OutlookTable.GetRowCount)
Dim OutlookReplyToThisMail As Object
Set OutlookReplyToThisMail = OutlookMail.Session.GetItemFromID(OutlookAr(UBound(OutlookAr), 0))
With OutlookReplyToThisMail.ReplyAll
.Subject = Sheet1.Cells(1 + i, 15) & "_" & .Subject
.HTMLBody = "<p style='font-family:calibri;font-size:13'>" & _
Sheet1.Cells(34, 2 + i) & "<br>" & "<br>" & _
Sheet1.Cells(35, 2 + i) & "<br>" & "<br>" & _
Sheet1.Cells(36, 2 + i) & Signature & .HTMLBody
.Display
End With
i = i + 1
Loop
End Sub

First of all, creating a new Outlook Application instance in the loop is not actually a good idea:
Do While Not IsEmpty(Cells(i + 1, 4))
Set OutlookApp = CreateObject("Outlook.Application")
Instead, consider moving the creation line above before the loop:
Set OutlookApp = CreateObject("Outlook.Application")
Do While Not IsEmpty(Cells(i + 1, 4))
In the code you are iterating over Excel cells and get corresponding selected items in Outlook.
it should only reply those which i highlighted in outlook email.
If you need to iterate over all selected items in Outlook you need to not rely on the Excel's data and have got a separate loop based on the number of selected items. For example:
Dim myOlExp As Outlook.Explorer
Dim myOlSel As Outlook.Selection
Set myOlExp = OutlookApplication.ActiveExplorer
Set myOlSel = myOlExp.Selection
For x = 1 To myOlSel.Count
If myOlSel.Item(x).Class = OlObjectClass.olMail Then
' For mail item, use the SenderName property.
Set oMail = myOlSel.Item(x)
Debug.Print oMail.SenderName
End If
Next

Related

Add code to macro to display different hyperlinks in different emails being sent from excel

How do I add different hyperlinks to excel email body text that goes out to different people? Each email would have a different hyperlink. This is the code I have so far:
Sub Button1_Click()
Dim rngCell As Range
Dim Rng As Range
Dim OutApp As Object
Dim OutMail As Object
Dim strBody As String
Dim EmailSubject As String
Dim SendToMail As String
Dim r As Long
Application.ScreenUpdating = False
With ActiveSheet
If .FilterMode Then .ShowAllData
End With
Set OutApp = CreateObject("Outlook.Application")
Set Rng = Range("T5", Cells(Rows.Count, "T").End(xlUp))
For Each rngCell In Rng
r = rngCell.Row
If Range("J" & r).Value = "" And Range("K" & r).Value <> "" And Range("I" & r).Value <= Date Then
Range("J" & r).Value = Date
Set OutMail = OutApp.CreateItem(0)
strBody = "According to my records, your " & Range("A" & r) & Range("S" & r).Value & _
" contract is due for review. This contract expires " & Range("K" & r).Value & _
". It is important you review this contract ASAP and email me " & _
"with any changes that are made. If it is renewed or rolled over, please fill out the " & _
"Contract Cover Sheet which can be found in the Everyone folder " & _
"and send me the Contract Cover Sheet along with the new original contract."
SendToMail = Range("T" & r).Value
EmailSubject = Range("A" & r).Value
On Error Resume Next
With OutMail
.To = SendToMail
.CC = "email address removed for privacy reasons"
.BCC = ""
.Subject = EmailSubject
.Body = strBody
.Display ' You can use .Send
End With
End If
Next rngCell
Application.ScreenUpdating = True
End Sub
In the code you are dealing with a plain text message body:
.Body = strBody
To set up hyperlinks you need to prepare an HTML markup for the message body and then set up the HTMLBody property which returns a string representing the HTML body of the specified item.
The Outlook object model supports three main ways of customizing the message body:
The Body property returns or sets a string representing the clear-text body of the Outlook item.
The HTMLBody property of the MailItem class returns or sets a string representing the HTML body of the specified item. Setting the HTMLBody property will always update the Body property immediately. For example:
Sub CreateHTMLMail()
'Creates a new e-mail item and modifies its properties.
Dim objMail As Outlook.MailItem
'Create e-mail item
Set objMail = Application.CreateItem(olMailItem)
With objMail
'Set body format to HTML
.BodyFormat = olFormatHTML
.HTMLBody = "<HTML><BODY>Enter the message text here. </BODY></HTML>"
.Display
End With
End Sub
The Word object model can be used for dealing with message bodies. See Chapter 17: Working with Item Bodies for more information.
You should be able to just add the hyperlinks that i am guessing are already in cells in your excel sheet. If the links are arranged as such that they are in cells next to the name rows you can just use your current for loops. Just add & Range("INPUT CELL WITH HYPERLINK HERE").value. Should not be a problem for the major part.
If the hyper links are only a few and you need to check whome to send which you can just use and IF condition within the for loop.

How to create emails from Excel table?

I have a table in Excel. It is built as follows:
|Information on food|
|date: April 28th, 2021|
|Person|Email|Apples|Bananas|Bread|
|------|-----|------|-------|-----|
|Person_A|person_A#mailme.com|3|8|9|
|Person_B|person_B#mailme.com|10|59|11|
|Person _C|person_C#maime.com|98|12|20|
There is also a date field in the table. For a test, this could be set to todays date.
Based on this information, I am looking for a VBA code which prepares an email to each of the listed persons and is telling them what they have eaten on the specific date.
I need to access several fields in the table, and at the same time loop through the email addresses. Then I would like VBA to open Outlook and prepare the emails. Ideally not send them so I can take a final look before I send the mails.
It would be fine to access certain cells specifically via ranges etc. I am using Excel/Outlook 2016.
How can this be achieved in VBA?
Assuming the data is a named table and title/date are above the corner of the table as shown in your example. Also all the rows of the table have valid data. The emails are prepared and shown but not sent (unless you change the code where shown).
Option Explicit
Sub EmailMenu()
Const TBL_NAME = "Table1"
Const CSS = "body{font:12px Verdana};h1{font:14px Verdana Bold};"
Dim emails As Object, k
Set emails = CreateObject("Scripting.Dictionary")
Dim ws As Worksheet, rng As Range
Dim sName As String, sAddress As String
Dim r As Long, c As Integer, s As String, msg As String
Dim sTitle As String, sDate As String
Set ws = ThisWorkbook.Sheets("Sheet1")
Set rng = ws.ListObjects(TBL_NAME).Range
sTitle = rng.Cells(-1, 1)
sDate = rng.Cells(0, 1)
' prepare emails
For r = 2 To rng.Rows.Count
sName = rng.Cells(r, 1)
sAddress = rng.Cells(r, 2)
If InStr(sAddress, "#") = 0 Then
MsgBox "Invalid Email: '" & sAddress & "'", vbCritical, "Error Row " & r
Exit Sub
End If
s = "<style>" & CSS & "</style><h1>" & sDate & "<br>" & sName & "</h1>"
s = s & "<table border=""1"" cellspacing=""0"" cellpadding=""5"">" & _
"<tr bgcolor=""#ddddff""><th>Item</th><th>Qu.</th></tr>"
For c = 3 To rng.Columns.Count
s = s & "<tr><td>" & rng.Cells(1, c) & _
"</td><td>" & rng.Cells(r, c) & _
"</td></tr>" & vbCrLf
Next
s = s & "</table>"
' add to dictonary
emails.Add sAddress, Array(sName, sDate, s)
Next
' confirm
msg = "Do you want to send " & emails.Count & " emails ?"
If MsgBox(msg, vbYesNo) = vbNo Then Exit Sub
' send emails
Dim oApp As Object, oMail As Object, ar
Set oApp = CreateObject("Outlook.Application")
For Each k In emails.keys
ar = emails(k)
Set oMail = oApp.CreateItem(0)
With oMail
.To = CStr(k)
'.CC = "email#test.com"
.Subject = sTitle
.HTMLBody = ar(2)
.display ' or .send
End With
Next
oApp.Quit
End Sub

How to send specific row data to the respective users from an Excel sheet?

I have an Excel sheet with data of users as shown below in table. Here I need to send the email to user their specific details containing in column A,B,C.
Using this code, I can only send the multiple row data in multiple email, but I need to send the multiple row data in single mail to respective user.
Sub BulkMail()
Application.ScreenUpdating = False ThisWorkbook.Activate Dim outMail As Outlook.MailItem
'Creating variable to hold values of different items of mail
Dim sendTo, subj, msg, Name, Company, Time As String
Dim lstRow As Long
'My data is on sheet "Exceltip.com" you can have any sheet name.
ThisWorkbook.Sheets("Sheet2").Activate
'Getting last row of containing email id in column 1.
lstRow = Cells(Rows.Count, 1).End(xlUp).Row
'Variable to hold all email ids
Dim rng As Range
Set rng = Range("A2:A" & lstRow)
'initializing outlook object to access its features
Set outApp = New Outlook.Application
On Error GoTo cleanup 'to handle any error during creation of object.
'Loop to iterate through each row, hold data in of email in variables and send
'mail to each email id.
For Each cell In rng
sendTo = Range(cell.Address).Offset(0, 0).Value2
subj = Range(cell.Address).Offset(0, 1).Value2
msg = Range(cell.Address).Offset(0, 2).Value2
Name = Range(cell.Address).Offset(0, 3).Value2
Company = Range(cell.Address).Offset(0, 4).Value2
Time = Range(cell.Address).Offset(0, 5).Value2
On Error Resume Next 'to hand any error during creation of below object
Set outMail = outApp.CreateItem(0)
'Writing and sending mail in new mail
With outMail
.To = sendTo
.Subject = subj
strbody = msg & vbNewLine & Name & " " & Company & " " & Time
.Body = strbody
.Send 'this send mail without any notification. If you want see mail
'before send, use .Display method.
End With
On Error GoTo 0 'To clean any error captured earlier
Set outMail = Nothing 'nullifying outmail object for next mail
Next cell 'loop ends
cleanup: 'freeing all objects created
Set outApp = Nothing
Application.ScreenUpdating = True
Application.ScreenUpdating = True
End Sub
I have added two columns. In column F there are the users' name (without duplicate.I have added the last user. He doesn't have messages). In column G there are how many message there are for the user in column F.
Here an example
I have got a problem with foreach cell... and then I used the for loop (classic).
In this example I used another for. The first for check the user's name and with the second for check how many messages there are for the user. I have put one or more messages in the strbody variable. When the second for is finished, I insert the number of messages for the user (COLUMN G) and then send the email.
My Code:
Sub bulkMail()
Const COLUMN_F As Byte = 6
Const COLUMN_G As Byte = 7
Application.ScreenUpdating = False
ThisWorkbook.Activate
Dim outMail As Outlook.MailItem
'Creating variable to hold values of different items of mail
Dim sendTo, subj, msg, Name, Company, Time As String
Dim lstRow As Long
'add variable
Dim numberUsers, i,j, numberMsg As Integer
'My data is on sheet "Exceltip.com" you can have any sheet name.
ThisWorkbook.Sheets("Sheet2").Activate
'Getting last row of containing email id in column 1.
lstRow = Cells(Rows.Count, 1).End(xlUp).Row
'count number users in Column F -> 6. Here there are the users without duplicate name.
numberUsers = Cells(Rows.Count, COLUMN_F).End(xlUp).Row
'Variable to hold all email ids
'i didn't use range because i had problems with foreach (i don't know why)
'Dim rng As Range
'Set rng = Range("A2:A" & lstRow)
'initializing outlook object to access its features
Set outApp = New Outlook.Application
On Error GoTo cleanup 'to handle any error during creation of object.
'Loop to iterate through each row, hold data in of email in variables and send
'mail to each email id.
For i = 2 To numberUsers
numberMsg = 0
strbody = ""
'For Each cell In rng
For j = 2 To lstRow
'Name = Range(cell.Address).Offset(0, 3).Value2
Name = Cells(j, 1) ' I get the name column A
If (Cells(i, COLUMN_F) = Name) Then
numberMsg = numberMsg + 1 ' count the number of messages
sendTo = Cells(j, 1) 'Range(cell.Address).Offset(0, 0).Value2 - COLUMN A
subj = Cells(j, 5) 'Range(cell.Address).Offset(0, 1).Value2 - COLUMN E
msg = Cells(j, 4) 'Range(cell.Address).Offset(0, 2).Value2 - COLUMN D
'Name = cells(j,1)Range(cell.Address).Offset(0, 3).Value2
Company = Cells(j, 2) 'Range(cell.Address).Offset(0, 4).Value2 - COLUMN B
Time = Cells(j, 3) 'Range(cell.Address).Offset(0, 5).Value2 - COLUMN C
strbody = strbody & msg & vbNewLine & Name & " " & Company & " " & Time & vbNewLine
'Debug.Print (strbody)
End If
Next j 'loop ends
Cells(i, COLUMN_G) = numberMsg ' get in COLUMN G the number of message for the user in COLUMN F
On Error Resume Next 'to hand any error during creation of below object
'check if there is almost a message for a user
If (numberMsg <> 0) Then
Set outMail = outApp.CreateItem(0)
'Writing and sending mail in new mail
With outMail
.To = sendTo
.Subject = subj
'strbody = msg & vbNewLine & Name & " " & Company & " " & Time
.Body = strbody
.Send 'this send mail without any notification. If you want see mail
'before send, use .Display method.
End With
On Error GoTo 0 'To clean any error captured earlier
Set outMail = Nothing 'nullifying outmail object for next mail
End If
'Next cell 'loop ends
Next i
cleanup: 'freeing all objects created
Set outApp = Nothing
Application.ScreenUpdating = True
Application.ScreenUpdating = True
End Sub
before trying my code check if my cells match yours.

Sending Outlook email in VBA, any subject with a colon ":" causes the email to be sent blank

I have a macro that copies a word document content, pastes it into an email. Then pulls email addresses and names from Excel, and sends each person the email with an attachment. (Essentially a mailmerge)
Problem is, anytime the subject has a colon ":", the email message sends as blank. This doesn't happen if I save the email, nor when I display it. Only happens if it is immediately sent.
Here is the code:
Option Explicit
Sub SendInitialEmail()
'directory of email body
Dim dirEmailBody As String
' Directory of email template
dirEmailBody = _
"C:\Users\me\Documents\Email Body.docx"
Dim wordApp As Word.Application
Dim docEmail As Document
' Opens email template and copies it
Set wordApp = New Word.Application
Set docEmail = wordApp.Documents.Open(dirEmailBody)
docEmail.Content.Copy
Dim outEdit As Document
Dim outApp As Outlook.Application
Set outApp = New Outlook.Application
Dim outMail As MailItem
' The names/emails to send too
Dim sendName As String, sendEmail As String, _
ccEmail As String, siteName As String
Dim row As Integer
' Was only testing on one row, but generally this pulls from
'a sheet of names and email addresses to send an email with attachments too.
For row = 1 to 1
sendName = actSheet.Cells(row, 1)
sendEmail = actSheet.Cells(row, 2)
ccEmail = actSheet.Cells(row, 3)
siteName = actSheet.Cells(row, 4)
Set outMail = outApp.CreateItem(olMailItem)
With outMail
.SendUsingAccount = outApp.Session.Accounts.Item(1)
.To = "myemailaddress to test#gmail.com"
.BodyFormat = olFormatHTML
.subject = _
"Is the error cause of a colon: Email test to me"
' it was
Set outEdit = .GetInspector.WordEditor
outEdit.Content.Paste
outEdit.Range(0).InsertBefore ("Dear " & sendName & "," & vbNewLine)
' If I do display, it shows up correctly.
' If I display then send it is fine (workaround)
.Send
End With
Next row
docEmail.Close
wordApp.Quit
End Sub
Remove the following:
Set outEdit = .GetInspector.WordEditor
outEdit.Content.Paste
outEdit.Range(0).InsertBefore ("Dear " & sendName & "," & vbNewLine)
and add:
`.Body = "Dear " & sendName & "," & vbNewLine & docEmail.Content.Text`
The colon is not the problem.
Try to use the Chr() command, in this case the ":" is Chr(58)

Excel VBA For Each Case Send Email

Hi I am using the below code to send multiple emails based on different cases. (Email addressess and other information are stored in a worksheet) The code works fine however I have 20 different cases (example below only shows two). Putting the outlook application code within each case seems cumbersome.
Is there a method to perform the email against each case without having to express the outlook code within each case?
I have searched using For Each Case without any luck. Help is greatly appreciated.
Sub RequestUpdates()
Dim olApp As Outlook.Application
Dim olMail As Outlook.MailItem
Dim blRunning As Boolean
Dim email As String
Dim fname As String
Dim fllink As String
Dim cpname As String
Dim v As Integer
Dim y As Integer
Dim rng As Range
Dim rdate As Date
Dim signature As String
v = Sheets("Contributors").Range("A" & Rows.Count).End(xlUp).Row
Set rng = Sheets("Contributors").Range("A1")
rdate = Sheets("Contributors").Range("A1").Value
For y = 0 To v
Select Case rng.Offset(1 + y, 0).Value
Case "PCR"
email = Sheets("Contributors").Range("E4").Value
fname = Sheets("Contributors").Range("D4").Value
fllink = Sheets("Contributors").Range("F4").Value
cpname = Sheets("Contributors").Range("B4").Value
'get application
blRunning = True
Set olApp = GetObject(, "Outlook.Application")
If olApp Is Nothing Then
Set olApp = New Outlook.Application
blRunning = False
End If
On Error GoTo 0
Set olMail = olApp.CreateItem(olMailItem)
With olMail
.Display
End With
signature = olMail.HTMLBody
With olMail
'Specify the email subject
.Subject = "test " & rdate
'Specify who it should be sent to
'Repeat this line to add further recipients
.Recipients.Add email
'specify the file to attach
'repeat this line to add further attachments
'.Attachments.Add "LinktoAttachment"
'specify the text to appear in the email
.HTMLBody = "<p>Hi " & fname & ",</p>" & _
"<P>Please follow the link below to update the " & cpname & " test" _
& "For month ending " & rdate & ".</p>" & _
"<P> </br> </p>" & _
fllink & _
"<P> </br> </p>" & _
"<p>If you face issues with file access please contact me directly.</p>" & _
"<P>Note: xxxxx.</p>" & _
signature
'Choose which of the following 2 lines to have commented out
.Display 'This will display the message for you to check and send yourself
'.Send ' This will send the message straight away
End With
Case "NFG"
email = Sheets("Contributors").Range("E6").Value
fname = Sheets("Contributors").Range("D6").Value
fllink = Sheets("Contributors").Range("F6").Value
cpname = Sheets("Contributors").Range("B6").Value
'get application
blRunning = True
Set olApp = GetObject(, "Outlook.Application")
If olApp Is Nothing Then
Set olApp = New Outlook.Application
blRunning = False
End If
On Error GoTo 0
Set olMail = olApp.CreateItem(olMailItem)
With olMail
.Display
End With
signature = olMail.HTMLBody
With olMail
'Specify the email subject
.Subject = "Test" & rdate
'Specify who it should be sent to
'Repeat this line to add further recipients
.Recipients.Add email
'specify the file to attach
'repeat this line to add further attachments
'.Attachments.Add "LinktoAttachment"
'specify the text to appear in the email
.HTMLBody = "<p>Hi " & fname & ",</p>" & _
"<P>Please follow the link below to update the " & cpname & " component Test" _
& "For month ending " & rdate & ".</p>" & _
"<P> </br> </p>" & _
fllink & _
"<P> </br> </p>" & _
"<p>If you face issues with file access please contact me directly.</p>" & _
"<P>Note: Test.</p>" & _
signature
'Choose which of the following 2 lines to have commented out
.Display 'This will display the message for you to check and send yourself
'.Send ' This will send the message straight away
End With
End Select
Next
End Sub
I see two cases you showed follow one template, how about creating sub which sends emails retreiving subject, to etc. from parameters and then calling it from within Select Case with proper values passed?

Resources