I have a excel sheet with personal information such as name, email address etc. and I also have a VBA code that when a cell in a specific range is selected (range R in this case) then call the VBA macro to send a mail.
But how do I assign the email address of the specific person to my VBA code?
For example:
if I click on cell R5, then the VBA macro should start running to send a mail to the email address in cell M5 and cell O5 or if I click on cell R10, then it should email to the email address in cell M10 and cell O10.
See below the code I have so far:
When I click on any cell in range R, the following VBA macro is triggered
Option Explicit
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If Selection.Count = 1 Then
If Not Intersect(Target, Range("R6:R1000000")) Is Nothing Then
Call Send_Email
End If
End If
End Sub
The macro Send_Email:
Sub Send_Email()
Dim EmailApp As Outlook.Application
Dim NewEmailItem As Outlook.MailItem
Dim Scr As String
Set EmailApp = New Outlook.Application
Set NewEmailItem = EmailApp.CreateItem(olMailItem)
NewEmailItem.To = ****** here should be the cell reference ******
'NewEmailItem.CC = ****** here should be the cell reference ******
NewEmailItem.Subject = "abcd"
With NewEmailItem
.HTMLBody = "Hello abcd" etc.
End With
End Sub
Here is the sample code which does exactly the same - shows how to send an email to a list of recipients based on data stored in a workbook. The recipient email addresses must be in column A, and the body text of the email must be in the first text box on the active sheet:
Sub Sample()
'Setting up the Excel variables.
Dim olApp As Object
Dim olMailItm As Object
Dim iCounter As Integer
Dim Dest As Variant
Dim SDest As String
'Create the Outlook application and the empty email.
Set olApp = CreateObject("Outlook.Application")
Set olMailItm = olApp.CreateItem(0)
'Using the email, add multiple recipients, using a list of addresses in column A.
With olMailItm
SDest = ""
For iCounter = 1 To WorksheetFunction.CountA(Columns(1))
If SDest = "" Then
SDest = Cells(iCounter, 1).Value
Else
SDest = SDest & ";" & Cells(iCounter, 1).Value
End If
Next iCounter
'Do additional formatting on the BCC and Subject lines, add the body text from the spreadsheet, and send.
.BCC = SDest
.Subject = "FYI"
.Body = ActiveSheet.TextBoxes(1).Text
.Send
End With
'Clean up the Outlook application.
Set olMailItm = Nothing
Set olApp = Nothing
End Sub
In your scenario with a separate function for sending emails you can pass the required data via parameters.
Related
I want to code a VBA such that the mail can be sent only if the user fills in details in rows. If not, an alert showing "Cannot send update. Fill the details completely" should pop up on the users screen.
Eg: The user has to fil Columns "A to J" and "M". If not they cannot send mail and pop up should ask them to enter it.
I have the following code as below,
Sub MAIL()
Dim EmailApp As Outlook.Application
Dim Source As String
Set EmailApp = New Outlook.Application
Dim EmailItem As Outlook.MailItem
Set EmailItem = EmailApp.CreateItem(olMailItem)
EmailItem.To = "abc#gmail.com"
EmailItem.Subject = " "
EmailItem.HTMLBody = ""
Source = ThisWorkbook.FullName
EmailItem.Attachments.Add Source
EmailItem.Send
End Sub
Please help me provide alerts to users. I am completely new to this.
Please, use the next function. It will check if at least a cell is filled in all columns of the range ("A:J, M:M"). In such a case it returns True. Otherwise, it send a relevant message and returns false, stopping the mail sending:
Function checkIfOK() As Boolean
Dim rng As Range, ar As Range, i As Long
Set rng = Range("A:J,M:M")
For Each ar In rng.Areas
For i = 1 To ar.Columns.count
If WorksheetFunction.CountA(ar.Columns(i)) > 1 Then
MsgBox "Column " & Split(ar.Columns(i).cells(1).Address, "$")(1) & " is empty..."
Exit Function
End If
Next i
Next ar
checkIfOK = True
End Function
You have to use it in your code in the next way:
Sub MAIL()
If Not checkIfOK Then Exit Sub 'it stop the code here if the function returns False
Dim EmailApp As Outlook.Application, Source As String
Set EmailApp = New Outlook.Application
Dim EmailItem As Outlook.MailItem
Set EmailItem = EmailApp.CreateItem(olMailItem)
EmailItem.To = "abc#gmail.com"
EmailItem.Subject = " "
EmailItem.HtmlBody = ""
Source = ThisWorkbook.fullName
EmailItem.Attachments.Add Source
EmailItem.Send
End Sub
The function has been built on the above mentioned assumption. I asked you in my comment "How this to be appreciated?" and you did not answer anything...
I have an Excel file with 1000+ rows. There is data in column A, addressee 1 email in column M, addressee 2 email in column N and validation column O.
Validation column mechanism: If the value in the cell is <0 then the row should be taken into the email.
I need a macro to draft one email and the content of email should be merged table of all rows that have negative value in column O (key).
The email should be adressed via Bcc to email addresses from column M and Cc to email addresses in column N.
The subject and content of the email is not that important, but I'd like to adjust it. For the purpose of the exercise it can be "Generic title", "Generic Content".
After the email is drafted, I need to click "send" in Outlook.
After sending an email for a row, the value in column O for this row should change to a green cell with "OK" value.
DUMMY DATA BEFORE MACRO RUN
THE MAIL
DUMMY DATA AFTER MACRO RUN
The code below creates a seperate email for each row instead of one email with cell values from column A combined in one table (or some other form) as the email body. How do I re-arrange it so it creates one email?
Sub Send_mails()
Dim OutApp As Object
Dim OutMail As Object
Dim cell as Range
Application.ScreenUpdating = False
Set OutApp = CreateObject("Outlook.Application")
For Each cell in Worksheets("test1"). Columns("O").Cells
Set OutMail = OutApp.CreateItem(0)
If cell.Value < 0 Then
With OutMail
.Bcc = Cells(cell.Row, "M").Value
.Cc = Cells(cell.Row, "N").Value
.Subject = "Gneric Subject"
.Body = "Generic body text, Values from column A for each row meeting the condition, to be put here"
.display
End With
Cells(cell.Row, "O").Value = "OK"
Set OutMail = Nothing
End If
Next Cell
End Sub
I am not really sure if I understood what you need!
From your dummy data I created a table and named it tbClient.
Here is the code and the mail output!
You need to set a Reference to Microsoft Word or you change the code to use Late Binding.
Option Explicit
Public ws As Worksheet
Public ol As ListObject
Public olRng As Range
Sub copyTabletoEmail()
Dim olCol As Integer
Application.ScreenUpdating = False
Set ws = Sheets("Test1")
Set ol = ws.ListObjects("tbClient")
' remove table filter buttons
If Not ol.ShowAutoFilterDropDown Then ol.ShowAutoFilterDropDown = True
' clear table filters
If ol.AutoFilter.FilterMode Then ol.AutoFilter.ShowAllData
' get validation column
olCol = ol.ListColumns("Validation").Index
' filter table
ol.Range.AutoFilter field:=olCol, Criteria1:="<0", Operator:=xlOr
' remove table filter buttons
ol.ShowAutoFilterDropDown = False
' select table to copy
Set olRng = ol.Range
' create mail
Call CreateMail
' Change values on 'Validation' column
ol.ListColumns(olCol).DataBodyRange.SpecialCells(xlCellTypeVisible).Value = "OK"
' clear table filters
If ol.AutoFilter.FilterMode Then ol.AutoFilter.ShowAllData
Application.ScreenUpdating = True
End Sub
Sub CreateMail()
Dim OutApp As Object
Dim OutMail As Object
Dim OutInsp As Object
Dim mailTo As String, mailCC As String
Dim olCol As Integer
Dim rCell As Range
Dim addRng As Range
On Error GoTo errHandler
Set OutApp = CreateObject("Outlook.Application")
Set OutMail = OutApp.CreateItem(0)
' display mail
OutMail.display
' If you're sending the same message to everyone the next 2 lines can be moved outside of the loop
OutMail.Subject = "Generic Subject"
' Range of mail addresses
olCol = ol.ListColumns("Client mail").Index
Set addRng = ol.ListColumns(olCol).DataBodyRange.SpecialCells(xlCellTypeVisible)
' get the mail addresses
For Each rCell In addRng
With OutMail
mailTo = mailTo & rCell.Value & ";"
mailCC = mailCC & rCell.Offset(0, 1).Value & ";"
End With
Next rCell
OutMail.to = mailTo
OutMail.cc = mailCC
' Declare word Variables
Dim oWrdDoc As Word.Document
Dim oWdEditor As Word.Editors
' Get the Active Inspector
Set OutInsp = OutMail.GetInspector
' Get the document within the inspector
Set oWrdDoc = OutInsp.WordEditor
' Greetings
Dim bodyMessage As String
bodyMessage = "Hi Kapcer," & vbNewLine
oWrdDoc.Range.InsertBefore bodyMessage
' Paste the table
olRng.Copy
oWrdDoc.Range(Len(bodyMessage), Len(bodyMessage)).Paste
exitRoutine:
Application.CutCopyMode = False
' clear
Set OutMail = Nothing
Set OutApp = Nothing
Set ws = Nothing
Exit Sub
errHandler:
' Open immediate window to see the error
Debug.Print Err.Number, Err.Description
Resume exitRoutine
End Sub
If you are trying to send a single email, cc'd to all of the recipients in column N and bcc'd to all of the recipients in column M, then use logic like this:
Sub Send_mails()
Dim OutApp As Object
Dim OutMail As Object
Dim Recipient as Object
Dim ws as Worksheet
Dim cell as Range
Set ws = ThisWorkbook.Worksheets("test1") ' Assuming ThisWorkbook is correct
Application.ScreenUpdating = False
Set OutApp = CreateObject("Outlook.Application")
Set OutMail = OutApp.CreateItem(0)
For Each cell in ws.Columns("O").Cells ' Better to limit this to the used range so you don't loop over 1 million rows.
If cell.Value < 0 Then
With OutMail
Set Recipient = .Recipients.Add(ws.Cells(cell.Row, "M").Value
Recipient.Type = olBcc
Set Recipient = .Recipients.Add(ws.Cells(cell.Row, "N").Value
Recipient.Type = olCc
' If you're sending the same message to everyone the next 2 lines can be moved outside of the loop
.Subject = "Gneric Subject"
.Body = "Generic body text, Values from column A for each row meeting the condition, to be put here"
End With
ws.Cells(cell.Row, "O").Value = "OK"
End If
Next Cell
OutMail.display
Set OutMail = Nothing
Set Recipient = Nothing
Set OutApp as Nothing
Set ws = Nothing
End Sub
I haven't run this, so there could be bugs.
There are other posts about the same thing, but I can't get it to work with my variables.
I have two columns of data that use IF statements IF(Asus!C:C=TODAY(),"Promo Today","").
I want to detect when a cell turns into "Promo Today" and send an email to the recipients. From my understanding, the email address had to be defined in a cell. I tried to get that into the code.
Columns 2 and 3, as I tried to target in the code, are the columns in which the IF statements are located. Do I have to target a row as well?
Private Sub Worksheet_Change()
Dim sEmailBodyp1 As String
Dim sEmailSubject As String
Dim sEmailTo As String
Dim Outlook As Object
Dim MasterCheck As Worksheet
sEmailTo = MasterCheck.Range("D2").Value
sEmailSubject = MasterCheck.Range("E2").Value
sEmailBodyp1 = MasterCheck.Range("F2").Value
If Target.Column = 2 And Target.Value = "Promo Today" Then
With CreateObject("Outlook.Application").CreateItem(0)
.To = sEmailTo
.Subject = sEmailSubject
.Body = sEmailBodyp1
.Send
End With
End If
End Sub
Briefing
On VBA there're several ways to access a Sheet and the most common are through:
The sheet name, which you can set on the Excel Sheet (and the user can change this)
And then call in your code like this:
Dim myWorksheet As Worksheet
Set myWorksheet = Worksheets("Sheet1") 'The user defined Excel sheet name.
The Microsoft Excel Object sheet (which you can find on the left pane)
And you can simply call it like this (assuming its name is Sheet1):
Sheet1.Activate
Your code
So, going back to your code, since the variable MasterCheck is not initialized, we can use the first method and initialize its value:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim sEmailBodyp1 As String
Dim sEmailSubject As String
Dim sEmailTo As String
Dim Outlook As Object
Dim MasterCheck As Worksheet
Set MasterCheck = Sheets("MySheet") 'Change "MySheet" with your sheet name
sEmailTo = MasterCheck.Range("D2").Value
sEmailSubject = MasterCheck.Range("E2").Value
sEmailBodyp1 = MasterCheck.Range("F2").Value
If Target.Column = 2 And Target.Value = "Promo Today" Then
With CreateObject("Outlook.Application").CreateItem(0)
.To = sEmailTo
.Subject = sEmailSubject
.Body = sEmailBodyp1
.Send
End With
End If
End Sub
Something like this should work:
Private Sub Worksheet_Change(ByVal Target As Range)
If Intersect(Target, Range("B:B")) Is Nothing Or Target.Cells.Count > 1 Then Exit Sub
Dim sEmailBodyp1 As String
Dim sEmailSubject As String
Dim sEmailTo As String
Dim Outlook As Object
Dim MasterCheck As Worksheet
Set MasterCheck = ActiveWorkbook.Sheets("SheetName") 'Change this with your sheet name
sEmailTo = MasterCheck.Range("D2").Value
sEmailSubject = MasterCheck.Range("E2").Value
sEmailBodyp1 = MasterCheck.Range("F2").Value
If Target.Value = "Promo Today" Then
With CreateObject("Outlook.Application").CreateItem(0)
.To = sEmailTo
.Subject = sEmailSubject
.Body = sEmailBodyp1
.Send
End With
End If
End Sub
I'm trying to get all the cells from my Excel worksheet in column 1.
My code throws an error.
"object required"
Public Sub emailList()
'Setting up the Excel variables.
Dim olApp As Object
Dim olMailItm As Object
Dim iCounter As Integer
Dim Dest As Variant
Dim SDest As String
'Create the Outlook application and the empty email.
Set olApp = CreateObject("Outlook.Application")
Set olMailItm = olApp.CreateItem(0)
'Using the email, add multiple recipients, using a list of addresses in column A.
With olMailItm
SDest = ""
For iCounter = 1 To WorksheetFunction.CountA(Workbooks("Book1.xls").Sheets(1).Columns(1))
If SDest = "" Then
SDest = Range.Cells(iCounter, 1).Value
Else
SDest = SDest & ";" & Range.Cells(iCounter, 1).Value
End If
Next iCounter
'Do additional formatting on the BCC and Subject lines, add the body text from the spreadsheet, and send.
.BCC = SDest
.Subject = "FYI"
.Body = ActiveSheet.TextBoxes(1).Text
.Send
End With
'Clean up the Outlook application.
Set olMailItm = Nothing
Set olApp = Nothing
End Sub
How do I get a worksheet object?
I tried
Workbooks("Book1.xls").Sheet1.Columns(1)
but this also throws an error.
I'm running the code in Outlook and have an open Excel window.
You will need to add a reference to the Excel object library, which is done in the VBA editor, under Tools / Add References. Just having Excel open isn't enough.
I am trying to copy an entire sheet into an email body and the sheet is already filtered and hides rows. I want to copy only the visible rows into the email. I thought my code would do that but when the people reply to the emails, the entire sheet (both hidden and unhidden) appears in the email. Any ideas?
Sub Send_Range_Or_Whole_Worksheet_with_MailEnvelope()
'Working in Excel 2002-2013
Dim AWorksheet As Worksheet
Dim Sendrng As Range
Dim rng As Range
On Error GoTo StopMacro
With Application
.ScreenUpdating = False
.EnableEvents = False
.Application.DisplayAlerts = False
End With
'Fill in the Worksheet/range you want to mail
'Note: if you use one cell it will send the whole worksheet
Set Sendrng = Worksheets("Test").Range("A1").SpecialCells(xlCellTypeVisible)
'Remember the activesheet
Set AWorksheet = ActiveSheet
With Sendrng
' Select the worksheet with the range you want to send
.Parent.Select
'Remember the ActiveCell on that worksheet
Set rng = ActiveCell
'Select the range you want to mail
.Select
' Create the mail and send it
ActiveWorkbook.EnvelopeVisible = True
With .Parent.MailEnvelope
' Set the optional introduction field thats adds
' some header text to the email body.
.Introduction = "Test"
With .Item
.To = "test#email.com"
.CC = ""
.BCC = ""
.Subject = "Test"
.Send
End With
End With
'select the original ActiveCell
rng.Select
End With
This was essentially taken from this Example 2 of Ron de Bruin, with some code from another example.
The code below seems to work.
You will have to fill it in with Ranges selection/activation and other details as needed.
EDIT The final step is sending the email (as per an added request of the OP). DoEvents added thanks to an answer to Excel VBA: Sent Outlook email does not include pasted Range
Sub SendEmail()
Dim OutlookApp As Object
'Dim OutlookApp As Outlook.Application
Dim MItem As Object
'Dim MItem As Outlook.MailItem
'Create Outlook object
Set OutlookApp = CreateObject("Outlook.Application")
'Set OutlookApp = New Outlook.Application
Dim Sendrng As Range
Set Sendrng = Worksheets("Test").Range("A1").SpecialCells(xlCellTypeVisible)
Sendrng.Copy
'Create Mail Item
Set MItem = OutlookApp.CreateItem(0)
'Set MItem = OutlookApp.CreateItem(olMailItem)
With MItem
.To = "test#email.com"
.Subject = "Test"
.CC = ""
.BCC = ""
'.Body = "a"
.Display
End With
SendKeys "^({v})", True
DoEvents
With MItem
.Send
End With
Set OutlookApp = Nothing
Set MItem = Nothing
End Sub
Since you did not state it is mandatory to use VBA (at least when this answer was first posted), you might:
Go to Home -> Find & Select -> Go To Special -> Visible cells only. Then copy and paste into your email. That worked for me.