How do I add the code that will run automatically when a date is entered. If the code includes other cells - do they need to be populated first. The idea is when today's date is entered and email will be sent. The code Email works but I need for the code to run automatically.
Private Sub Worksheet_SelectionChange(ByVal Target As Range)
If IsDate(Range("A1").Value) Then
'MsgBox "Plase enter a date in A1"
'response = MsgBox(msg, vbYesNo)
'If response = vbYes Then
email
Else
End If
'End If
End Sub
Sub email()
Dim r As Range
Dim cell As Range
Set r = Range("A1:S20")
For Each cell In r
If cell.Value = Date Then
Dim Email_Subject, Email_Send_From, Email_Send_To, _
Email_Cc, Email_Bcc, Email_Body As String
Dim Mail_Object, Mail_Single As Variant
Email_Subject = Cells(cell.Row, "C").Value
Email_Send_From = "Jean#test.com"
Email_Send_To = "Joe#test.com"
Email_Cc = ""
Email_Bcc = ""
Email_Body = "Hi " & Cells(cell.Row, "c").Value _
& vbNewLine & vbNewLine & _
Cells(cell.Row, "D").Value & _
" has been submited"
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_Body
.send
End With
End If
Next
Exit Sub
debugs:
If Err.Description <> "" Then MsgBox Err.Description
End Sub
I believe this is what you want. When the value in A1 is updated, it will first validate if the entry is a date. If entry is not a valid date, you will receive the first MsgBox in code.
If the entry is a valid date, the user will be asked if they want to send the email. If they select No, the macro will end. If they select Yes, your Email Sub will begin to execute.
Private Sub Worksheet_Change(ByVal Target As Range)
Dim Response As String
If Not IsDate(Range("A1").Value) Then
MsgBox "Plase enter a valid date in A1"
Else
Response = MsgBox("Do you want to send email?", vbYesNo)
If Response = vbYes Then Call Email
End If
End Sub
If you do not want the user to have to choose Yes or No to send the email, and you want it to happen as soon as the entry in A1 has been validated as a date, then change your IF statement to this:
If Not IsDate(Range("A1").Value) Then
MsgBox "Plase enter a valid date in A1"
Else
Call Email
End If
Side Note
You should also update this to only execute when a certain range (or maybe individual cell in this case) is changed. Otherwise, the macro will fire when ANY cell is changed. Instead, determine the range that should trigger this macro, and then call the macro when the changed cell overlaps (or Intersects) with your pre-determined range.
Related
I'm struggling to find a way to pull the first column value matching with the same row from the cell.value found and insert it on the email body.
In others words: Where there is the word "Send" on my worksheet it should grab the matching name from the same row in the first column ("A") and put it on my text body.
Is this possible?
My code below
Sub email()
Dim r As Range
Dim cell As Range
Set r = Range("F2:F100")
For Each cell In r
If cell.Value = "Send" Then
Dim Email_Subject, Email_Send_From, Email_Send_To, _
Email_Cc, Email_Body As String
Dim Mail_Object, Mail_Single As Variant
Dim Machine_Code As Long
Dim Machine_Type As Long
Email_Subject = "Reminder to perform activity"
Email_Send_From = "George#JKhoney.com"
Email_Send_To = "xsoxperience#JKhoney.com"
Email_Cc = ""
Email_Body = "Dear, This is a friendly reminder. There are pending actions regarding your activities please take actions accordingly" & ". Due date on " & cell.Value & " This is an automatic e-mail with no response needed"
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
.Body = Email_Body
.Send
End With
End If
Next
debugs:
If Err.Description <> "" Then MsgBox Err.Description
Call email_2
End Sub
UPDATE
I have reworked my code to look like the following:
Private Sub Worksheet_Change(ByVal Target As Range)
Call notify
End Sub
Sub notify()
Dim rng As Range
For Each rng In Range("N2:N502")
If (rng.Value = "Expired") Then
Call mymacro(rng.Address)
End If
Next rng
End Sub
Private Sub mymacro(theValue As String)
Dim xOutApp As Object
Dim xOutMail As Object
Dim xMailBody As String
Dim myAddress As String
Dim myChemical As String
myAddress = Application.WorksheetFunction.Index(Range("A2:Q502"), Application.WorksheetFunction.Match("Expired", Range("N2:N502"), 0), 15)
myChemical = Application.WorksheetFunction.Index(Range("A2:Q502"), Application.WorksheetFunction.Match("Expired", Range("N2:N502"), 0), 3)
Set xOutApp = CreateObject("Outlook.Application")
Set xOutMail = xOutApp.CreateItem(0)
xMailBody = "Hello" & vbNewLine & vbNewLine & _
"This email is to let you know that you have an expired reference standard" & vbNewLine & _
"The Reference Standard that has expired is: " & myChemical & vbNewLine & vbNewLine & _
"Thank you," & vbNewLine & _
"Spreadsheet Manager"
On Error Resume Next
With xOutMail
.To = myAddress
.CC = ""
.BCC = ""
.Subject = "Expired Reference Standard"
.Body = xMailBody
.Display 'or use .Send
End With
On Error GoTo 0
Set xOutMail = Nothing
Set xOutApp = Nothing
End Sub
This new code now populates the emails with the correct fields, but it is getting stuck on the first entry that equals "Expired" in column N. It knows that there are multiple instances of "Expired" because when I change myChemical in the message to theValue multiple emails populate with different cell values. Is there a way to fix the code to avoid this error as is, or would I have to add a For-Next statement into the code?
That's an ambitious project. You don't need the code to be continuously running if you have it triggered from a Worksheet_Change event. You can use that event to "watch" just the contents of specific rows, columns or ranges, and run the code when a cell in the watched range is changed by the user. (https://learn.microsoft.com/en-us/office/vba/api/excel.worksheet.change)
The Worksheet_Change event runs in the Sheet module and uses the concept of the "target" range, which is the range or cell that triggered the macro to run. If it is a single cell, you now have the address of that cell and from there you can deduce the row number and get other data in that row, or data related to that cell dependent on your sheet layout.
You can now to construct the body text with the details you need.
I have code in which if column I, it will look at that value and then send an email if it matches any of my limits. Then I have also included a refresh anytime I edit another column.
This code is in ThisWorkbook
Private Sub Workbook_Open()
Call Worksheet_Calculated
End Sub
This is my code in Sheet1 that will run the operation if anything in column G changes.
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Address Like "$F$*" Then
Call Worksheet_Calculated
End If
End Sub
This code is in a module. It checks to see if any value in column I is any of of the MyLimit Values, if it is, in column I, it will say sent or not sent. If sent, an email will be generated.
Option Explicit
Public Sub Worksheet_Calculated()
Dim FormulaRange As Range
Dim NotSentMsg As String
Dim MyMsg As String
Dim SentMsg As String
Dim MyLimita As Double
Dim MyLimitb As Double
Dim MyLimitc As Double
Dim MyLimitd As Double
NotSentMsg = "Not Sent"
SentMsg = "Sent"
'Above the MyLimit value it will run the macro
MyLimita = 100
MyLimitb = 50
MyLimitc = 10
MyLimitd = 1
'Set the range with Formulas that you want to check
'This is the column that shows how many days left
Set FormulaRange = Range("H5:H25")
On Error GoTo EndMacro:
For Each FormulaCell In FormulaRange.Cells
With FormulaCell
If IsNumeric(.Value) = False Then
MyMsg = ""
ElseIf (.Value = MyLimita Or .Value = MyLimitb Or .Value = MyLimitc Or .Value = MyLimitd) Then
MyMsg = SentMsg
If .Offset(0, 1).Value = NotSentMsg Then
Call Mail_with_outlook(FormulaCell)
End If
Else
MyMsg = NotSentMsg
End If
Application.EnableEvents = False
.Offset(0, 1).Value = MyMsg
Application.EnableEvents = True
End With
Next FormulaCell
ExitMacro:
Exit Sub
EndMacro:
Application.EnableEvents = True
MsgBox "Some Error occurred." _
& vbLf & Err.Number _
& vbLf & Err.Description
End Sub
The above code will call another module which will populate the email that I would like to send.
Option Explicit
Public FormulaCell As Range
Public Sub Mail_with_outlook(FormulaCell As Range)
Dim OutApp As Object
Dim OutMail As Object
Dim strto As String, strcc As String, strbcc As String
Dim strsub As String, strbody As String
Set OutApp = CreateObject("Outlook.Application")
Set OutMail = OutApp.CreateItem(0)
'Change the parenthesis for column that the email is in
strto = Cells(FormulaCell.Row, "K").Value
strcc = ""
strbcc = ""
strsub = "Payment Notification (PO --Enter PO # Here--)"
'Change the parenthesis for the Column that the POC is in
strbody = "Hi " & Cells(FormulaCell.Row, "J").Value & vbNewLine & vbNewLine & _
"This is a reminder to pay for a licensing/maintenance bill in: " & Cells(FormulaCell.Row, "H").Value & " days." & _
vbNewLine & vbNewLine & "Line 2" & _
vbNewLine & "Line 3" & _
vbNewLine & "Line 4" & _
vbNewLine & "Line 5" & _
vbNewLine & "Line 6"
With OutMail
.To = strto
.CC = strcc
.BCC = strbcc
.Subject = strsub
.Body = strbody
'You can add a file to the mail like this
'.Attachments.Add ("C:\test.txt")
.Display ' or use .Send
End With
Set OutMail = Nothing
Set OutApp = Nothing
End Sub
I want to continue running this code on start up and whenever column G is edited, but only in Sheet1.
I want when column I is negative to copy that entire row into sheet2.
I'm currently working on a VBA sheet which will email out certain cell values based on the true/false value of a relative toggle button. I am working with a rather large amount of toggle buttons and was looking into adding a function to return a string of the cell values with the corresponding toggle button values. However, my current string's return variable is blank.
I currently have the following email sub which is called via a command button:
Public Sub Send_Email_Using_VBA()
Dim Email_Subject, Email_Send_From, Email_Send_To, _
Email_Cc, Email_Bcc, Email_Body, First_Name, Second_Name, Third_Name As String
Dim example As Range
Dim callOutString As String
Dim Mail_Object, Mail_Single As Variant
Email_Subject = "Check Sheet Completed"
Email_Send_From = "myemail#email.com"
Email_Send_To = "name#email.com"
Email_Cc = ""
Email_Bcc = ""
Email_Body = ""
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_Body & bodyString 'trying to call/add resulting string from the below sub
.Send
End With
debugs:
If Err.Description <> "" Then MsgBox Err.Description
End Sub
And I am attempting to call/return the string value of "bodyString" from the following sub:
'Checks sheet for true toggle boxes which need immediate attention or notice and adds those descriptors to the email body.
Private Sub CommandButton5_Click()
Dim bodyString As String
Dim x As Integer
x = 1
'togglebutton2 check to see if active
If ToggleButton2 = True Then
If x = 1 Then
bodyString = "This item: " & Range("A14").Value & " is Bad"
End If
x = x + 1
End If
If x = 1 Then
MsgBox "No items need attention"
bodyString = "No items need attention"
Else
MsgBox x - 1 & " Items Need Attention:" & vbCrLf & vbCrLf & bodyString
bodyString = x - 1 & " Items Need Attention:" & vbCrLf & vbCrLf & bodyString
End If
End Sub
In the above final If/Else statement, I am using the MsgBox function to display the bodyString to ensure that it is storing the correct data.
For example, the MsgBox will display: No items need attention. However the bodyString variable returns a blank.
The variable bodyString is defined within the event handler `Sub CommandButton5_Click(), and its value cannot be returned out of this subroutine.
To address this issue, move the declaration of bodyString out of the Sub CommandButton5_Click() routine and place it such that it's declared at the module-level (outside of all functions and subroutines). Then Sub Send_Email_Using_VBA() will be able to access that variable and its contents will be maintained.
How can I write an excel macro which will send an automatic e-mail when one of the certain range of cells' value has been changed?
The problem is the range of cells I have chosen has formula which is directly linked to other spreadsheet cells. And those cells' data has been updated by a web connection query of Excel. As shown in the picture below, the a1:b5 range has formula linked to d1:e5 range.
Here is my syntax
Private Sub Worksheet_Change(ByVal Target As Range)
Dim rngChangeCells As Range
Dim objOutlookApp As Outlook.Application
Dim objMailItem As Outlook.MailItem
Dim strMailBody As String
On Error Resume Next
Set rngChangeCells = Intersect(Target, Me.Range("a1:b5"))
On Error GoTo 0
If Not rngChangeCells Is Nothing Then
Set objOutlookApp = New Outlook.Application
Set objMailItem = objOutlookApp.CreateItem(olMailItem)
strMailBody = "Cell(s) " & rngChangeCells.Address(False, False) & _
" in the worksheet '" & Me.Name & "' were modified on " & _
Format$(Now, "mm/dd/yyyy") & " at " & Format$(Now, "hh:mm:ss") & _
" by " & Environ$("username") & "."
With objMailItem
.To = "myagmarchuluun#gmail.com"
.Subject = "It has changed"
.Body = strMailBody
.Display
End With
Set rngChangeCells = Nothing
Set objOutlookApp = Nothing
Set objMailItem = Nothing
End If
End Sub
enter image description here
Something like this.
Note: Change YourMacroName to the name of your macro in the code.
If you want the code to work for another cell or more cells you can change the range in the event.
Private Sub Worksheet_Change(ByVal Target As Range)
If Target.Cells.Count > 1 Then Exit Sub
If Not Application.Intersect(Range("A1"), Target) Is Nothing Then
If IsNumeric(Target.Value) And Target.Value > 200 Then
Call YourMacroName
End If
End If
End Sub
Test this example macro to create/display a Outlook mail with a small text message.
You must copy this macro in a standard module and not in the worksheet module, see this page how.
Note: I use .Display in the code to display the mail, you can change that to .Send
Do not forget to change Call YourMacroName to Call Mail_small_Text_Outlook in the Change event.
Sub Mail_small_Text_Outlook()
'For Tips see: http://www.rondebruin.nl/win/winmail/Outlook/tips.htm
'Working in Excel 2000-2016
Dim OutApp As Object
Dim OutMail As Object
Dim strbody As String
Set OutApp = CreateObject("Outlook.Application")
Set OutMail = OutApp.CreateItem(0)
strbody = "Hi there" & vbNewLine & vbNewLine & _
"Cell A1 is changed" & vbNewLine & _
"This is line 2" & vbNewLine & _
"This is line 3" & vbNewLine & _
"This is line 4"
On Error Resume Next
With OutMail
.To = "ron#debruin.nl"
.CC = ""
.BCC = ""
.Subject = "This is the Subject line"
.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
End Sub
https://www.rondebruin.nl/win/s1/outlook/bmail9.htm