Send Reminder through Outlook - excel

Good day all,
i am looking to alter the below VBA Code to send reminder to filtered range to each User based on specific text in column "H" "Send Reminder" and filtered range must be pasted into email below the body lines (Means Column A1:E1 by User wise filtered range).
Basically VBA code will reduce our work from more than hours to Milli seconds.
Problems encountered:
in our daily work we have so many todo list which needs to remind employee by employee wise with filtered list to each person will consume more than 2 hours to sort our data. Now the below code works but not filtered by User wise so its completely insufficient to use it properly. sending each email wise but filtered table also needs to place in the body of the emails is worthy. Hence time does not reduce much more than that.
Hence i am Looking to alter the below code as per my requirement.
Existing VBA Code:
Sub Send_Reminder()
Dim wStat As Range, i As Long
Dim dam As Object
For Each wStat In Range("H2", Range("H" & Rows.Count).End(xlUp))
If wStat.Value = "Send Reminder" Then
i = wStat.Row
Set dam = CreateObject("Outlook.Application").CreateItem(0)
dam.To = Range("I" & i).Value
dam.Cc = "" 'Range("F" & i).Value
dam.Subject = Range("B" & i).Value
dam.Body = "Hi " & Range("E" & i).Value & "," & vbCr & vbCr & _
"This is to remind you that " & Range("B" & wStat.Row).Value & " " & _
"Report is due today." & vbCr & vbCr & _
"Cheers!"
dam.FlagRequest = "Follow up" ' We set the Follow up Flag
dam.FlagDueBy = Format(DateAdd("d", 1, Date) + TimeValue("09:30:00"), "dd/mm/yyyy hh:mm") ' We set the due date for the reminder two days from today
dam.Display '.Sent
'
dam.Display '.Send
wStat.Value = "Sent"
End If
Next
MsgBox "Emails Sent"
End Sub

Related

VBA Data pasting in wrong cells sometimes

I am attempting to write a macro that:
Iterates over a list of employee IDs, identifies whether it needs a report generated or not then, filters a large dataset to include only that employee, grab several different columns, and paste them into a formatted sheet. It will then copy that sheet and save it into a file directory as a binary file.
The code works as expected sometimes, but other times, it seems to be pasting the all the data in a different row (it varies, but is usually between rows 8800 and 9200). I want it to paste in Row 2. The only clue that I have found to indicate the cause is that column S, where Gross Margin is stored, seems to have a couple hundred rows of data above where the table starts (only in some cases though). All data is still lining up in the correct rows.
Sub SplitFile()
Application.DisplayAlerts = False
Set wb = Application.ActiveWorkbook
Set pivots = wb.Sheets("Pivots")
Set repository = wb.Sheets("Repository")
Set listing = wb.Sheets("Customer Listing")
For Each rep In pivots.Range("A4:A" & pivots.Range("A3").End(xlDown).Row)
If rep.Offset(0, 1) <> "" Then
Debug.Print rep
lastRow = repository.Range("A1").End(xlDown).Row
repName = rep.Offset(0, 1).Value
repDistrict = rep.Offset(0, 2).Value
folderPath = pivots.Range("B1").Value & "\" & repDistrict
repository.Range("A1:AU" & lastRow).AutoFilter Field:=33, Criteria1:=rep
'EEID and Name
repository.Range("AG2:AH" & lastRow).SpecialCells(xlCellTypeVisible).Copy listing.Range("A2")
'Source
repository.Range("F2:F" & lastRow).SpecialCells(xlCellTypeVisible).Copy listing.Range("C2")
'Cust ID
repository.Range("H2:H" & lastRow).SpecialCells(xlCellTypeVisible).Copy listing.Range("D2")
'Cust Name
repository.Range("K2:K" & lastRow).SpecialCells(xlCellTypeVisible).Copy listing.Range("E2")
'Address Details
repository.Range("S2:U" & lastRow).SpecialCells(xlCellTypeVisible).Copy listing.Range("F2")
'Predominant Trade, Active/Inactive, Start Date
repository.Range("W2:Y" & lastRow).SpecialCells(xlCellTypeVisible).Copy listing.Range("I2")
'Region & District
repository.Range("AA2:AB" & lastRow).SpecialCells(xlCellTypeVisible).Copy listing.Range("L2")
'Pay Terms
repository.Range("AQ2:AQ" & lastRow).SpecialCells(xlCellTypeVisible).Copy listing.Range("N2")
'Revenue and Margin
repository.Range("L2:M" & lastRow).SpecialCells(xlCellTypeVisible).Copy listing.Range("O2")
repository.Range("N2:N" & lastRow).SpecialCells(xlCellTypeVisible).Copy listing.Range("R2")
repository.Range("O2:O" & lastRow).SpecialCells(xlCellTypeVisible).Copy listing.Range("S2") 'my guess is this is about where the problem is.
'Sort Data
listing.Columns("A:W").Sort key1:=listing.Range("P1"), order1:=xlDescending, Header:=xlYes
'Formulas
lastListingRow = listing.Cells(1000000, 1).End(xlUp).Row
listing.Range("Q2:Q" & lastListingRow).Formula = "=IFERROR(P2/O2,"""")"
listing.Range("T2:T" & lastListingRow).Formula = "=IFERROR(S2/R2,"""")"
listing.Range("U2:V" & lastListingRow).Formula = "=IFERROR(O2-R2,"""")"
listing.Range("W2:W" & lastListingRow).Formula = "=IFERROR(ROUND((Q2-T2)*10000,0),"""")"
'Paste formulas
'lastListingRow = listing.Cells(1000000, 1).End(xlUp).Row
'listing.Range("Q2").Copy listing.Range("Q3:Q" & listingLastRow)
'listing.Range("Q2").Copy listing.Range("T3:T" & listingLastRow)
'listing.Range("U2").Copy listing.Range("U3:V" & listingLastRow)
'listing.Range("W2").Copy listing.Range("W3:W" & listingLastRow)
If Dir(folderPath, vbDirectory) = "" Then
MkDir (folderPath)
End If
listing.Copy
Set newWb = Application.ActiveWorkbook
newWb.SaveAs folderPath & "\" & repDistrict & "-" & rep & "-" & repName & "-" & pivots.Range("H1"), FileFormat:=50
newWb.Close
listing.Range("A2:R9000").Value = ""
repository.ShowAllData
End If
Next
End Sub
I am not using option explicit as I tend to code mostly in python and have grown used to "duck typing".
I'd appreciate any help, and can clarify if you need it. I've never run into this problem before, but I've written several programs like it.
I don't know why this occurred, but I fixed it by replacing listing.Range("A2:R9000").Value = "" with listing.Rows("2:100000").delete.

Fill email text with cell values from a list of variable length

I have a list in column "A" with company names. Those company's employees are in column "B". In column "C" the date they started working.
Some have 10 employees some have 1 employee. I would like to send an e-mail with a standard text. In that text there should be the names of the employees and the start dates.
Sub mailen()
Dim namen As String
Dim r As Range
Dim inhoud As String
Dim names As string
Dim dates As string
inhoud = "Hello client," & "<br>" & _
"Here some text that explains why we send this e-mail." & "<br>" & _
"It is about your employee(s): " & names & " " & "<br>" & _
"These employee(s) are working for you from the dates: " & dates & "." & "<br>"
For Each r In Range("O2", Range("O2").End(xlDown))
If r.Value = r.Offset(-1, 0).Value Then
r.Value = r.Value
Else: namen = r.Value
With CreateObject("Outlook.Application").createitem(0)
.To = namen
.Subject = "Test"
.HTMLbody = inhoud
.attachments.Add ("C:\.pdf")
.send
End With
End If
Next r
End Sub
In column "O" are the e-mail addresses to send the e-mail to.
I need to fill the variable names with the names and the variable dates with the dates.
Try this code:
Sub SubMailen()
'Declarations.
Dim RngMailingAddressList As Range
Dim RngCompanyNameList As Range
Dim RngEmployeeNameList As Range
Dim RngStartingDateList As Range
Dim RngTarget01 As Range
Dim RngTarget02 As Range
Dim StrMailingAddress As String
Dim StrMessage As String
'Setting ranges as the first cell of their column.
Set RngMailingAddressList = Range("O2")
Set RngCompanyNameList = Range("A2")
Set RngEmployeeNameList = Range("B2")
Set RngStartingDateList = Range("C2")
'Resetting ranges to cover the whole list (based upon RngMailingAddressList).
Set RngMailingAddressList = Range(RngMailingAddressList, RngMailingAddressList.End(xlDown))
Set RngCompanyNameList = Range(RngCompanyNameList, RngCompanyNameList.Offset(RngMailingAddressList.Rows.Count - 1))
Set RngEmployeeNameList = Range(RngEmployeeNameList, RngEmployeeNameList.Offset(RngMailingAddressList.Rows.Count - 1))
Set RngStartingDateList = Range(RngStartingDateList, RngStartingDateList.Offset(RngMailingAddressList.Rows.Count - 1))
'Covering each cell in RngMailingAddressList.
For Each RngTarget01 In RngMailingAddressList
'Checking if the address has not been encountered before.
If Excel.WorksheetFunction.CountIf(Range(RngMailingAddressList.Cells(1, 1), RngTarget01), RngTarget01.Value) = 1 Then
'Setting StrMailingAddress.
StrMailingAddress = RngTarget01.Value
'Setting first part of StrMessage.
StrMessage = "Hello client," & "<br>" & _
"Here some text that explains why we send this e-mail." & "<br>" & _
"It is about your employee(s):" & "<br>"
'Covering all the cells in RngCompanyNameList.
For Each RngTarget02 In RngCompanyNameList
'Checking if RngTarget02 has the same company name as the row of the address the mail is about to be sent.
If RngTarget02.Value = Cells(RngTarget01.Row, RngCompanyNameList.Column).Value Then
'Adding name and starting date of the employee to StrMessage.
StrMessage = StrMessage & Cells(RngTarget02.Row, RngEmployeeNameList.Column).Value & " (working for you from " & Cells(RngTarget02.Row, RngStartingDateList.Column).Value & ")" & "<br>"
End If
Next
'Setting and sending the mail.
With CreateObject("Outlook.Application").createitem(0)
.To = StrMailingAddress
.Subject = "Test"
.HTMLbody = StrMessage
.attachments.Add ("C:\.pdf")
.send
End With
End If
Next
End Sub
I though that putting employees' name and starting date together would make more sense. The code checks if the mail address has been already encountered and do not send more than a mail each. It creates a list of employees' names and starting date based upon the company name specified in the same row of the given address. This mean that if you have 2 (or more) different e-mails for the same company, 2 (or more) mails will be sent (1 for each e-mail) both with the full list of employees' name and starting date of the given company. The code should work independently from the sorting order of the list.
I've never sent an e-mail via code, so i assume that the part of your code that deal with such task and that i've integrated in my code is already working. The code can be improved by adding a mean to specify the message part now set as "Here some text that explains why we send this e-mail", another one to specify the subject of the e-mail and another one to specify a possible attachment to the e-mail.

How to cancel a case when interactive textbox selects cancel

So I am writing a case function that when an event (7 - Engaged) occurs an interactive textbox pops up asking the user to confirm this action. If they select OK the data is moved to another spreadsheet.
That all works dandy but probably needs revising to tidy it.
Anyways, the issue arises when the user selects cancel.
Instead of just leaving the function the line of data is deleted.
I believe this issue is the last couple lines deletes anything that is 7-engaged, but I haven't written a piece of code to bring the value down to 6 if the user cancels out.
Can anyone give me some hints?
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Source As Range)
' Maybe disable events whilst this code runs (and re-enable before exit)
' to prevent recursion.
' The three range rows are to move sepearate sections of data from pipeline into isolated blocks in tank.
If Source.Column <> 9 Then Exit Sub ' 9 = I
If Source.Cells.Count > 1 Then Exit Sub ' Check this first before making comparison on next line
If Source.Value <> "7 - engaged" Then Exit Sub
If MsgBox("Client status selected as engaged. Confirm to post to tank.", vbOKCancel) = vbOK Then
With ThisWorkbook.Worksheets("Tank") 'Produces an interactive dialoge box prompting the user to confirm they wish ti import to tank
'The code only fires if they confirm - if not, the line will remain in Pipeline.
Dim rowToPasteTo As Long
rowToPasteTo = .Cells(.Rows.Count, "B").End(xlUp).Row + 1
.Range("A" & rowToPasteTo & ":" & "D" & rowToPasteTo).Value = Sh.Range("A" & Source.Row & ":" & "M" & Source.Row).Value
.Range("G" & rowToPasteTo & ":" & "H" & rowToPasteTo).Value = Sh.Range("E" & Source.Row & ":" & "F" & Source.Row).Value
.Range("S" & rowToPasteTo & ":" & "U" & rowToPasteTo).Value = Sh.Range("K" & Source.Row & ":" & "M" & Source.Row).Value
End With
End If
If Source.Column = 9 And Source.Value = "7 - engaged" Then
Source.EntireRow.Delete
' The above line deleted the row from pipeline once it has been imported in Tank
End If
End Sub
I have now added this piece of code which negates the problem.
If MsgBox("Client status selected as engaged. Confirm to post to tank.", vbOKCancel) = vbCancel Then
Source.Value = "6 - KYC in progress" ' If cancel is selected the value goes back to Case 6 and the line is kept.
End If

VBA, Updating link to other workbook in formula daily

I am very new to VBA programming and have an issue.
I have a base file called liquidity forecast in which I fill data from other documents in. The documents I collect data from is updated every day so the date in the name changes every day.
The Name goes "(Date, "YYMMDD") & "SE_Laizy.xlsx" so an example would be, 160229SE_Laizy.xlsx
When I collect data I use Index match formula. My problem is trying to update the link within the formula by using a date value.
Currently I write it like this,
ActiveCell.Range((Cells(1, 1)), (Cells(1, 1))).FormulaR1C1 = _
"=INDEX('[" & Format(Date, "YYMMDD") & "SE_Laizy.xlsx"]Visa'!R1:R1048576,MATCH(R2C,'[" & Format(Date, "YYMMDD") & "SE_Laizy.xlsx"]Visa'!C1,0),MATCH(""Ub perioden"",'[" & Format(Date, "YYMMDD") & "SE_Laizy.xlsx"]Visa'!R2,0))"
All I get from this is a NA. Any help would be appreciated!
I've added a parent worksheet reference and broken the INDEX and
MATCH functions into the three primary sections.
With Worksheets("Sheet2")
.Cells(1, 1).FormulaR1C1 = _
"=INDEX('[" & Format(Date, "YYMMDD") & "SE_Laizy.xlsx]Visa'!C1:C16384, " & _
"MATCH(R2C,'[" & Format(Date, "YYMMDD") & "SE_Laizy.xlsx]Visa'!C1, 0), " & _
"MATCH(""Ub perioden"", '[" & Format(Date, "YYMMDD") & "SE_Laizy.xlsx]Visa'!R2, 0))"
End With
As noted, there were some misplaced quotes in the external workbook name. I'm not sure what to do with your Range object definition. For all intents and purposes, the one supplied simply resolves down to [A1].

Can I make my VBScript program ignore a field when reading from Excel?

I did a little bit of reading on what I am about to ask, but I couldn't find a specific answer.
I am writing a program in VBScript that will read an excel file and then update an Access Database.
It works great, but the problem I can foresee running into is thus:
What happens when the excel file has a blank on a specified field? I don't want the script file to update a "blank" to the database, I want it to be left unchanged in the database ONLY if there is a blank in the excel file. If not, proceed as normal.
Currently, it will read this as a blank and insert the blank into the row in my database.
Is this possible? For the script to basically ignore fields it reads (in Excel) that are blank while only updating (in the database) the fields that actually have data (in Excel) in them?
Currently, it says no in the field in the database. This is just a brief code example. In the Excel sheet, it says yes in the correct column.
Do Until objExcel.Cells(intRow,1).Value = ""
asset_Tag = objExcel.Cells(intRow, 1).Value
ebay = objExcel.Cells(intRow, 2).Value
intRow = intRow + 1
objRecordSet.Open "UPDATE Test SET Listed_Ebay = '" & ebay & "' WHERE Asset_Tag = '" & asset_Tag & "'", _
objConnection
Loop
If you are reluctant to add 20 If statements to your code, surely you could put Excel's native COUNTA functionality to make sure that there are 20 values before the update operation.
With objExcel
Do Until .Cells(intRow,1).Value = ""
If .Application.CountA(.Cells(intRow, 1).Resize(1, 20)) = 20 Then
asset_Tag = .Cells(intRow, 1).Value
ebay = .Cells(intRow, 2).Value
objRecordSet.Open "UPDATE Test SET Listed_Ebay = '" & ebay & "' WHERE Asset_Tag = '" & asset_Tag & "'", objConnection
End if
intRow = intRow + 1
Loop
End With
I had a guess a bit as to which 20 values were intended to be filled but I think you can get the idea.
EDIT NOTEĀ¹: reordered the code lines to maintain the intRow according to the loop.
EDIT NOTEĀ²: You may want to conditionally pass the original value back into the UPDATE query if the LEN of the new value is zero.
Dim qry as String
qry = "UPDATE Test SET " & _
"Listed_Ebay = Iif(CBool(Len('" & ebay & "')), '" & ebay & "', Listed_Ebay), " & _
"Listed_Amazon = Iif(CBool(Len('" & amzon& "')), '" & amzon & "', Listed_Amazon), " & _
"Listed_POS = Iif(CBool(Len('" & pos& "')), '" & pos & "', Listed_POS) " & _
"WHERE Asset_Tag = '" & asset_Tag & "'"
objRecordSet.Open qry, objConnection
I'm just making stuff up past the original one field example you provided but you should be able to transcribe this for your own 8 fields. I'm using LEN here on text values but comparing numbers to zero (or even their LEN would be appropriate.

Resources