Loop to write e-mail body based on query - ms-access

I want to write all the records in a query to an e-mail.
This writes the first record in the query.
MyBodyText = MailList("AccountName") & " - " & MailList("ExpirationDate")
I know I need some kind of loop.
MailList is defined as follows
Set MailList = db.OpenRecordset("qryDateEmail")
Option Compare Database
Option Explicit
Public Function ExpirationDate()
Dim strSQL
Dim db As DAO.Database
Dim MailList As DAO.Recordset
Dim MyOutlook As Outlook.Application
Dim MyMail As Outlook.MailItem
Dim Subjectline As String
Dim BodyFile As String
Dim fso As FileSystemObject
Dim MyBody As TextStream
Dim MyBodyText As String
Dim MyDecision As String
Dim strReportName As String
Dim strEnroll As String
Dim strWho As String
Dim strEmail As String
Set fso = New FileSystemObject
Set MyOutlook = New Outlook.Application
Set db = CurrentDb()
Set MailList = db.OpenRecordset("qryDateEmail")
Subjectline$ = "Expiration Date" & " " & Date
Set MyMail = MyOutlook.CreateItem(olMailItem)
Do While Not MailList.EOF
MyBodyText = MailList("AccountName") & " - " & MailList("ExpirationDate")
MailList.MoveNext
Loop
MyMail.To = "" & ""
MyMail.CC = CurrentUser() & ""
MyMail.Subject = Subjectline$
MyMail.Body = MyBodyText
MyMail.Display
strEmail = Now()
strWho = CurrentUser()
Set MyMail = Nothing
Set MyOutlook = Nothing
End Function

You could loop through the recordset, adding those values from each row to your body text.
Untested air code:
With MailList
Do While Not .EOF
MyBodyText = MyBodyText & !AccountName & _
" - " & !ExpirationDate & vbCrLf
.MoveNext
Loop
End With
Now I see you've added similar code to your question. The problem is that code overwrites the value of MyBodyText each time through the loop. Append to MyBodyText each time instead of replacing the text ...
MyBodyText = MyBodyText & "new text"
instead of ...
MyBodyText = "new text"

Related

Embedding an HTML file with images in an Outlook email generated by Excel VBA

I want to send a personalized email generated by Excel VBA.
The email contains personalized text followed by a html file that contains images.
I tried the following code but the images are not displayed.
Sub Mail_Outlook_With_Html_Doc()
Dim OutApp As Object
Dim OutMail As Object
Dim strbody As String
Dim oFSO As Object
Dim oFS As Object
Dim sText As String
Set oFSO = CreateObject("Scripting.FileSystemObject")
Set oFS = oFSO.OpenTextFile("C:\....\invite.htm")
Do Until oFS.AtEndOfStream
sText = oFS.ReadAll()
Loop
Set OutApp = CreateObject("Outlook.Application")
Set OutMail = OutApp.CreateItem(0)
'strbody = personalized email body generated here
On Error Resume Next
With OutMail
.display
.To = ToAdd
.CC =
.BCC = ""
.Subject = "Test Email"
.ReadReceiptRequested = True
' the html file is appended here to the personalized email body generated
.HTMLBody = strbody & sText
.Send
End With
On Error GoTo 0
Set OutMail = Nothing
Set OutApp = Nothing
End Sub
The invite.htm referred above contains images which are not visible when the email is sent. Neither in the email messages sent nor in the email messages received.
Here ia an example that works for me you need to adapt it according to your needs.
This will embed the image in the body of the email and will attach it from what I remember. Please note you need to display the email first and then send it that is the only way to show on different device, i learn that the hard way. It can be done via code as the below example if you want to display and review the email just comment out the .Send after you are happy you can press manually send.
Option Explicit
Dim titleName As String
Dim firstName As String
Dim lastName As String
Dim fullName As String
Dim clientEmail As String
Dim ccEmail As String
Dim bccEmail As String
Dim emailMessage As String
Sub GenerateInfo()
Dim WS As Worksheet
Dim lrow As Long
Dim cRow As Long
Set WS = ActiveSheet
With WS
lrow = .Range("E" & .Rows.Count).End(xlUp).Row
Application.ScreenUpdating = False
For cRow = 2 To lrow
If Not .Range("L" & cRow).value = "" Then
titleName = .Range("D" & cRow).value
firstName = .Range("E" & cRow).value
lastName = .Range("F" & cRow).value
fullName = firstName & " " & lastName
clientEmail = .Range("L" & cRow).value
Call SendEmail
.Range("Y" & cRow).value = "Yes"
.Range("Y" & cRow).Font.Color = vbGreen
Else
.Range("Y" & cRow).value = "No"
.Range("Y" & cRow).Font.Color = vbRed
End If
Next cRow
End With
Application.ScreenUpdating = True
MsgBox "Process completed!", vbInformation
End Sub
Sub SendEmail()
Dim outlookApp As Object
Dim outlookMail As Object
Dim sigString As String
Dim Signature As String
Dim insertPhoto As String
Dim photoSize As String
Set outlookApp = CreateObject("Outlook.Application")
Set outlookMail = outlookApp.CreateItem(0)
'Change only Mysig.htm to the name of your signature
sigString = Environ("appdata") & _
"\Microsoft\Signatures\Marius.htm"
If Dir(sigString) <> "" Then
Signature = GetBoiler(sigString)
Else
Signature = ""
End If
insertPhoto = "C:\Users\marius\Desktop\Presale.jpg" 'Picture path
photoSize = "<img src=""cid:Presale.jpg""height=400 width=400>" 'Change image name here
emailMessage = "<BODY style=font-size:11pt;font-family:Calibri>Dear " & titleName & " " & fullName & "," & _
"<p>I hope my email will find you very well." & _
"<p>Our <strong>sales preview</strong> starts on Thursday the 22nd until Sunday the 25th of November." & _
"<p>I look forward to welcoming you into the store to shop on preview.<p>" & _
"<p> It really is the perfect opportunity to get some fabulous pieces for the fast approaching festive season." & _
"<p>Please feel free to contact me and book an appointment." & _
"<p>I look forward to seeing you then." & _
"<p>" & photoSize & _
"<p>Kind Regards," & _
"<br>" & _
"<br><strong>Marius</strong>" & _
"<br>Assistant Store Manager" & _
"<p>"
With outlookMail
.To = clientEmail
.CC = ""
.BCC = ""
.Subject = "PRIVATE SALE"
.BodyFormat = 2
.Attachments.Add insertPhoto, 1, 0
.HTMLBody = emailMessage & Signature 'Including photo insert and signature
'.HTMLBody = emailMessage & Signature 'Only signature
.Importance = 2
.ReadReceiptRequested = True
.Display
.Send
End With
Set outlookApp = Nothing
Set outlookMail = Nothing
End Sub
Function GetBoiler(ByVal sFile As String) As String
Dim fso As Object
Dim ts As Object
Set fso = CreateObject("Scripting.FileSystemObject")
Set ts = fso.GetFile(sFile).OpenAsTextStream(1, -2)
GetBoiler = ts.readall
ts.Close
End Function

link back-end password protected access database within same location

I'm using the code below to link my bank-end database to the front-end. It works fine without having a password on the back-end DB. How do I use the same code with a password protected back-end file. NOTE: The following code is obtained from [Stackoverflow question][1]
[1]: https://stackoverflow.com/questions/3315306/how-can-a-relative-path-specify-a-linked-table-in-access-2007
Private Sub Form_Load()
Dim strOldConnect As String
Dim strNewConnect As String
Dim intSlashLoc As Integer
Dim intEqualLoc As Integer
Dim strConnect As String
Dim strFile As String
Dim strCurrentPath As String
strCurrentPath = CurrentProject.path
Dim tblDef As TableDef
Dim tblPrp As Property
For Each tblDef In CurrentDb.TableDefs
Debug.Print tblDef.Name
If tblDef.Connect & "." <> "." Then
strOldConnect = tblDef.Connect
intEqualLoc = InStr(1, strOldConnect, "=", vbTextCompare)
strConnect = Left(strOldConnect, intEqualLoc)
intSlashLoc = InStrRev(strOldConnect, "\", -1, vbTextCompare)
strFile = Right(strOldConnect, Len(strOldConnect) - intSlashLoc)
strNewConnect = strConnect & strCurrentPath & "\" & strFile
tblDef.Connect = strNewConnect
tblDef.RefreshLink
End If
Next tblDef
End Sub
The whole connection string for Access Microsoft ACE OLEDB 12.0 is:
Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\myFolder\myAccessFile.accdb; Jet OLEDB:Database Password=MyDbPassword;
See this link for reference https://www.connectionstrings.com/access/
In your case this would to the trick:
tblDef.Connect = "PWD=" & MyPassword & ";DATABASE=" & YourDatabasePath
I found a workaround myself and would like to share it, thank you.
Public Function DBconnect()
Dim Password As String
Dim FileName As String
Dim CurrentConnection As String
Dim AccessConnect As String
Dim NewConnection As String
Dim CurrentPath As String
Dim CurrentLocationEnd As Integer
AccessConnect = "MS Access;PWD=password;DATABASE="
Password = "password"
CurrentPath = CurrentProject.Path
Dim tblDef As TableDef
Dim tblPrp As Property
For Each tblDef In CurrentDb.TableDefs
Debug.Print tblDef.Name
If tblDef.Connect & "." <> "." Then
CurrentConnection = tblDef.Connect
CurrentLocationEnd = InStrRev(CurrentConnection, "\", -1, vbTextCompare)
FileName = Right(CurrentConnection, Len(CurrentConnection) - CurrentLocationEnd)
NewConnection = AccessConnect & CurrentPath & "\" & FileName
tblDef.Connect = NewConnection
tblDef.RefreshLink
End If
Next tblDef
End Function

Method Range of _Global object failed

I get a Method Range of Object _Global failed error due to the following code
SOMETIMES this code works SOMETIMES it doesnt. I understand the cause of it but not how to fix it. How do i specify which sheet this is selecting everytime so that it works consistently.
'Fill Formulas'
Range(columnLetter & "5").Select
Selection.AutoFill Destination:=Range(columnLetter & "5:" & columnLetter & "113"), Type:=xlFillDefault
Range(columnLetter & "143").Select
Selection.AutoFill Destination:=Range(columnLetter & "143:" & columnLetter & "251"), Type:=xlFillDefault
Here is all of my code
Public Sub AutoUpdateCancels()
Dim MySheetPath As String
Dim Xl As Excel.Application
Dim XlBook As Excel.Workbook
Dim XlSheet As Excel.Worksheet
Dim formattedDate As String
Dim lngRow As Long, intCol As Integer, db As DAO.Database, rst As DAO.Recordset, fld As DAO.Field
Dim columnLetter As String
Dim qdf As DAO.QueryDef
columnLetter = DLookup("[Column]", "[tblColumnIdentifier17]", "[WED] like #" & [Forms]![frmCancelsReporting]![txtCancelsWED] & "#")
formattedDate = Format(Date, "mm-dd-yyyy")
MySheetPath = "M:\Chris\Weekly Pulse\Cancel Report\2018\COM\Cancels Report - 2018v2.xlsx"
'Open Excel and the workbook and save a backup
Set Xl = CreateObject("Excel.Application")
Set XlBook = Xl.Workbooks.Open(MySheetPath, True)
Xl.Visible = True
XlBook.Windows(1).Visible = True
Set XlSheet = XlBook.Worksheets(11)
'Xl.ActiveWorkbook.SaveAs FileName:="M:\Chris\Weekly Pulse\Cancel Report\Backups\COM Backup 03-12-2018.xlsx"
'Clear Detail'
Xl.Range("A256:D371").Select
Xl.Selection.ClearContents
'Starting Row Number'
lngRow = 256
'Append New Detail'
Set db = CurrentDb
Set qdf = db.QueryDefs("qryCancelsReport")
qdf.Parameters("EndDate").Value = [Forms]![frmCancelsReporting]![txtCancelsWED]
Set rst = qdf.OpenRecordset()
Xl.Cells(lngRow, 1).CopyFromRecordset rst
'Fill Formulas'
Range(columnLetter & "5").Select
Selection.AutoFill Destination:=Range(columnLetter & "5:" & columnLetter & "113"), Type:=xlFillDefault
Range(columnLetter & "143").Select
Selection.AutoFill Destination:=Range(columnLetter & "143:" & columnLetter & "251"), Type:=xlFillDefault
Set rst = Nothing
Set db = Nothing
Set Xl = Nothing
Set XlBook = Nothing
Set XlSheet = Nothing
MsgBox ("Make sure to save over original worksheet not as backup")
End Sub
You were not referencing proper objects (e.g.: you used Xl.Range() instead of xlSheet.Range())
Avoid using Select/Selection/Activate/ActiveXXX coding pattern an use fully qualified range references (e.g. use xlSheet.Range() instead of Range())
So try this snippet:
With XlBook.Worksheets(11) ‘reference wanted sheet. From now on and till next ‘End With’ all referenced sheet members (like its Range()) are just a dot (.) away:
'Clear Detail'
.Range("A256:D371").ClearContents
'Starting Row Number'
lngRow = 256
'Append New
....
.Cells(lngRow, 1).CopyFromRecordset rst
'Fill Formulas'
.Range(columnLetter & "5").AutoFill Destination:=.Range(columnLetter & "5:" & columnLetter & "113"), Type:=xlFillDefault
.Range(columnLetter & "143").AutoFill Destination:=.Range(columnLetter & "143:" & columnLetter & "251"), Type:=xlFillDefault
End With

Multiselect listbox in Access 2010

So I have this search form that filters projects based on the designer type. The designer can be internal, external, or combination. It was originally done using a combobox. I was asked to make it so that the user can filter by multiple options, so I changed it to a listbox with the idea of using the multiselect option.
The listbox works fine, until I set the multiselct option to anything besides none. Then, all the projects are returned instead of the ones that are selected.
I'm not very experienced in Access or VBA so any assistance would be greatly appreciated. The following is the code for this section.
Private Sub toDesignerExcel_Click()
Dim db As DAO.Database
Dim rs1, rs2 As DAO.Recordset
Dim sSQL1, sSQL2, SourceExcel, FileName, Path As String
Set db = CurrentDb
sSQL1 = "Select ExcelPath from tblBackendFiles where Setting = 'ExcelDesignerParameters'"
sSQL2 = "Select Setting from tblBackendFiles where Code = 'SourceExcel'"
Set rs1 = db.OpenRecordset(sSQL1)
FileName = Nz(rs1!ExcelPath, "")
Set rs2 = db.OpenRecordset(sSQL2)
SourceExcel = Nz(rs2!Setting, "")
Path = SourceExcel + "\" + FileName
rs1.Close
rs2.Close
db.Close
Set rs1 = Nothing
Set rs2 = Nothing
Set db = Nothing
Shell "C:\WINDOWS\explorer.exe """ & Path, vbNormalFocus
End Sub
EDIT:
And also,
If Forms(formName).txtDesigner <> "" And Not IsNull(Forms(formName).txtDesigner) Then
If selEngConditions <> "" Then
selEngConditions = selEngConditions & " AND "
End If
selEngConditions = selEngConditions & "[Activity].[GWPDesigner] = '" & Forms(formName).txtDesigner & "'"
End If
I would do something like this :
Private Sub toDesignerExcel_Click()
Dim db As DAO.Database
Dim rs1, rs2 As DAO.Recordset
Dim sSQL1, sSQL2, SourceExcel, FileName, Path As String
Set db = CurrentDb
sSQL1 = "Select ExcelPath from tblBackendFiles where Setting = 'ExcelDesignerParameters' And [Tblbackendfiles] = '"
sSQL2 = "Select Setting from tblBackendFiles where Code = 'SourceExcel' And [Tblbackendfiles] = '"
For Each it In Me.ListBoxName.ItemsSelected
Set rs1 = db.OpenRecordset(sSQL1 & it & "'")
FileName = Nz(rs1!ExcelPath, "")
Set rs2 = db.OpenRecordset(sSQL2 & it & "'")
SourceExcel = Nz(rs2!Setting, "")
Path = SourceExcel + "\" + FileName
Shell "C:\WINDOWS\explorer.exe """ & Path, vbNormalFocus
rs1.Close
rs2.Close
Set rs1 = Nothing
Set rs2 = Nothing
Next it
db.Close
Set db = Nothing
End Sub
Where you basically iterate over all the selected items in the listbox. This adds each selected item from the listbox in the where clause of the query.
You can also try concatenating all the values and changing the query to something like :
And [Tblbackendfiles] In (" & comma_separated_list & ")

Keeping multiple file names while importing via transfertext

Private Sub Command38_Click()
Dim f As Object
Dim db As DAO.Database
Dim qdf As DAO.QueryDef
Dim strUpdate As String
Dim strFile As String
Dim strFolder As String
Dim varItem As Variant
Dim P As String
Dim DeleteEverything As String
DoCmd.SetWarnings False
DeleteEverything = "DELETE * FROM [ucppltr]"
DoCmd.RunSQL DeleteEverything
Set f = Application.FileDialog(3)
f.AllowMultiSelect = True
f.InitialFileName = "S:\Formware\outfile\ucppt12\Storage"
f.Filters.Clear
f.Filters.Add " Armored TXT Files", "*.asc"
If f.Show Then
For Each varItem In f.SelectedItems
strFile = Dir(varItem)
strFolder = Left(varItem, Len(varItem) - Len(strFile))
P = strFolder & strFile
DoCmd.TransferText acImportDelim, "UCPP Import Specification", "ucppltr", P, False
Next
End If
strUpdate = "PARAMETERS fileName Text;" & vbCrLf & _
"UPDATE ucppltr" & vbCrLf & _
"Set [File Name] = fileName"
Debug.Print strUpdate
Set db = CurrentDb
Set qdf = db.CreateQueryDef("", strUpdate)
qdf.Parameters("fileName") = strFile
qdf.Execute dbFailOnError
Set qdf = Nothing
Set db = Nothing
Set f = Nothing
MsgBox DCount("*", "ucppltr") & " Records were imported"
End Sub
As you can see from the code on import I want to store the file name and while it does work it doesn't work exactly how I need it to. When we do work for this client it is 5 files ate a time once a week so I would like it to save all 5 file names however it only saves the last one it imports. My question, is there a way to save each file name to each one ( I doubt that) or can I save all 5 file names to all the records I import instead of just the last file name?
I always have the option of only allowing a single import and making them import and append the table 5 times I just wanted to check to see if there is a more efficent way before doing so.
Thanks in advance for any help in this matter!
There is a problem in your logic. Inside the loop, strFile holds the current file name. So after your loop is finished, only the current (=last) file name is passed on to the query.
I made some changes, so the filenames are now stored in the new variable strFileList, delimited by a ";". Please check, if this is a feasible solution.
Private Sub Command38_Click()
Dim f As Object
Dim db As DAO.Database
Dim qdf As DAO.QueryDef
Dim strUpdate As String
Dim strFile As String
Dim strFolder As String
Dim varItem As Variant
Dim P As String
Dim DeleteEverything As String
' Variable to hold file list
Dim strFileList As String
DoCmd.SetWarnings False
DeleteEverything = "DELETE * FROM [ucppltr]"
DoCmd.RunSQL DeleteEverything
Set f = Application.FileDialog(3)
f.AllowMultiSelect = True
f.InitialFileName = "S:\Formware\outfile\ucppt12\Storage"
f.Filters.Clear
f.Filters.Add " Armored TXT Files", "*.asc"
If f.Show Then
For Each varItem In f.SelectedItems
strFile = Dir(varItem)
strFolder = Left(varItem, Len(varItem) - Len(strFile))
P = strFolder & strFile
DoCmd.TransferText acImportDelim, "UCPP Import Specification", "ucppltr", P, False
'Add file name to file list
strFileList = strFileList & strFile & ";"
Next
End If
strUpdate = "PARAMETERS fileName Text;" & vbCrLf & _
"UPDATE ucppltr" & vbCrLf & _
"Set [File Name] = fileName"
Debug.Print strUpdate
Set db = CurrentDb
Set qdf = db.CreateQueryDef("", strUpdate)
'Pass file list to query
qdf.Parameters("fileName") = strFileList
qdf.Execute dbFailOnError
Set qdf = Nothing
Set db = Nothing
Set f = Nothing
MsgBox DCount("*", "ucppltr") & " Records were imported"
End Sub