MS Access - Automatic email templates with Outlook - ms-access

I have attempted to modify the code in Sorceri's answer on StackOverflow, which demonstrates how to send an email using outlook. I tried to modify this to provide a custom email template, specific to the selected entry in the database:
Private Sub Emailtemplatebtn_Click()
Dim App As Outlook.Application
Dim Mail As MailItem
Set App = CreateObject("Outlook.application")
Set Mail = oApp.CreateItem(olMailItem)
oMail.Body = "Dear" &[Forename]& "," &vbCrLf& &vbCrLf& "It has been six months or longer since I last contacted you. Have there been any big gains with regard to impact?"
oMail.Subject = &[Project name]& "- check up"
oMail.To = &Email&
oMail.Send
Set oMail = Nothing
Set oApp = Nothing
End Sub
Unfortunately, the code doesn't work. The in-built VBA editor highlights the lines "oMail.Body", "oMail.subject", and "oMail.to" in red.
I figure that this could be a very helpful feature, as it will save users even more time - the script/database will essentially handle all of the user's copy and pasting!
Solution
After using "Option Explicit", it seemed to be easier to locate why the code was failing - variables were not properly defined (I added some "o"s, and took some away). Here is the finished code:
Put "Option Explicit" at the top of the VBA page for the form (the module for the form)
Use the following code, largely corrected by Andre.
Private Sub Emailtemplatebtn_Click()
Dim App As Outlook.Application
Dim oMail As MailItem
Set App = CreateObject("Outlook.application")
Set oMail = App.CreateItem(olMailItem)
oMail.Body = "Dear" & Me![Forename] & "," & vbCrLf & vbCrLf & "It has been six months or longer since I last contacted you. Have there been any big gains with regard to impact?"
oMail.Subject = Me![Project name] & "- check up"
oMail.To = Me!Email
oMail.Send
Set oMail = Nothing
Set App = Nothing
End Sub
Change oMail.send to oMail.display if you wish to make edits to the email before sending.

You want
Dim oMail As MailItem
(note the "o")
And the syntax for & is variable & "string", note the spaces and don't use two & in a row.
Those lines should be:
oMail.Body = "Dear" & [Forename] & "," & vbCrLf & vbCrLf & "It has been six months or longer since I last contacted you. Have there been any big gains with regard to impact?"
oMail.Subject = [Project name] & "- check up"
oMail.To = Email
If the variables are controls on your form, it is better to write Me!Forename or Me![Project name] so Access knows where to look for them.

Related

Unwanted Scientific Notation in MS Access

I'm encountering a very strange problem with MS Access. I have some VBA code used on a password reset form. The code hashes the input password and then saves the hash to a table of users. Here's a relevant snippit:
If newPW1 = newPW2 Then
MsgBox ("Passwords Match!")
hashPW = Encrypt(newPW1)
MsgBox ("HashedPW is " & hashPW)
updatePW = "UPDATE Users SET Password = " & hashPW & " WHERE Username = pwChangeUsrnm"
DoCmd.RunSQL (updatePW)
the MSGboxes are my debugging notes. I know the hash generates properly as a long string of numbers, all well and good. When I go into the datasheet for the Users table though, the number has always been converted into scientific notation.
Here's a screenshot of the data sheet. bob.smith is an example of what I end up with after the code runs, the other two are gibberish I entered manually. The field is formatted as a string, so I'm not sure why it would even try to convert the number into SN when as far as I can tell the item is always a string.
I'm thinking the error must creep in around the SQL query? If there's a better way of doing this then I'm all ears.
Thanks in advance for your help!
datasheet
design view
Complete code, just in case:
Option Compare Database
Private Sub Command84_Click()
Dim hashPW As String
Dim updatePW As String
Dim checkName As String
checkName = Nz(DLookup("Username", "Users", "Username = pwChangeUsrnm"), "aaa")
MsgBox ("checkName set to " & checkName)
If pwChangeUsrnm = checkName Then
MsgBox ("Username Found")
If newPW1 = newPW2 Then
MsgBox ("Passwords Match!")
hashPW = Encrypt(newPW1)
MsgBox ("HashedPW is " & hashPW)
updatePW = "UPDATE Users SET Password = " & hashPW & " WHERE Username = pwChangeUsrnm"
DoCmd.RunSQL (updatePW)
Else
MsgBox ("Passwords Do Not Match!")
End If
Else
MsgBox ("Username not found")
End If
End Sub
I think Andre has the right of it. I tried adjusting the hashing code to add a letter character and this worked, but then I needed to go back and add the single quote around the hashed PW value- which probably would have made the code work even without adding the letter:
If newPW1 = newPW2 Then
MsgBox ("Passwords Match!")
hashPW = Encrypt(newPW1)
MsgBox ("HashedPW is " & hashPW)
updatePW = "UPDATE Users SET Password = '" & hashPW & "' WHERE Username = pwChangeUsrnm"
DoCmd.RunSQL (updatePW)
A thanks to Zaph's second comment on security as well, I'll take that all into account. For the purposes of this database security isn't too much of a concern as it will be sitting behind existing security measures. The hashing of passwords is more just to avoid ever displaying the passwords in plain text. Nevertheless it's useful to know about these extra functions.

Access 2013 - Send an email automatically with outlook and Windows Task Scheduler

I have an access macro that runs a set of Netezza queries and uploads the results to a database. It then opens and refreshes an Excel file that utilizes this data and saves the file in a couple of locations. Finally it composes an automated email and sends it to a distribution list. When I manually run the macro, everything works 100% perfectly.
In order to make my life a bit easier, I am using Windows Task Scheduler (Windows 10) to automatically fire the macro once a day, and this is where my issue lies. Task Scheduler fires the macro off without a hitch, all of the queries refresh, the excel files are saved, but the e-mail is not sent.
Here is the code SendOutlookEmail code that I'm using
Sub sendOutlookEmail()
Dim oApp As Outlook.Application
Dim oMail As MailItem
Dim SpDate As String
Dim Signature As String
Dim StrPath As String
Dim StrFilter As String
Dim StrFile As String
SpDate = Format(Now() - 1, "yyyy-mm-dd")
Set oApp = CreateObject("Outlook.application")
Set oMail = oApp.CreateItem(olMailItem)
With oMail
.Display
End With
Signature = oMail.HTMLBody
With oMail
.SentOnBehalfOfName = "My Email"
.To = "CCO Reporting"
.Subject = "AHT - ACW Dashboard - " & SpDate
.HTMLBody = "<span LANG=EN>" _
& "<font FACE=SegoeUI SIZE = 3>" _
& "The IB/OB AHT - ACW reports have been updated and placed in the following folder:" _
& "<br><br>" _
& "<a href='File Location'>File Location</a>" & "<br><br><br></font></span>" _
& Signature
'.Attachments.Add (StrPath & StrFile)
'.Display
.Send
End With
On Error GoTo 0
Set oMail = Nothing
Set oApp = Nothing
End Sub
Here is the task scheduler settings
Task Scheduler
Possibly Outlook just doesn't have enough time to send the message, as it instantly gets closed after the message is moved to the outbox (.send doesn't send the message as far as I know, but just moves it to the outbox and triggers a send for all items in there).
Try to manually add a send/receive, to make Access wait for Outlook to actually send the mails (add this to your vba before the Set oApp = Nothing):
' Synchronizes (ie sends/receives) OL folders.
' Ref: http://msdn.microsoft.com/en-us/library/ff863925.aspx
Dim objNsp As Outlook.NameSpace
Dim colSyc As Outlook.SyncObjects
Dim objSyc As Outlook.SyncObject
Dim i As Integer
On Error GoTo SyncOL_Err
Set objNsp = oApp.Application.GetNamespace("MAPI")
Set colSyc = objNsp.SyncObjects
For i = 1 To colSyc.Count
Set objSyc = colSyc.Item(i)
Debug.Print objSyc.Name
objSyc.start
Next
Set objNsp = Nothing: Set colSyc = Nothing: Set objSyc = Nothing

Sending html email from VBA email program

I have written an email program for my organization the handles some very specialized things very well, things I could use Outlook or Gmail for. Now, the manager would like to send an occasional email to our small customer base, but I want the email body tto look professional and not send it as an attachment. I have cobbled together an html document that present in all browsers and has been validated. My problem is I can't figure out how to point the message body at the html document. Here is the salient code.
This is where all is set up:
Do While mailRs.EOF = False
'Me.AttachDoc = "C:\EmailFolder\CouponForm.pdf"
emTo = mailRs.Fields("EmailAddr").Value
emFrom = "SportsParkInfo#skokieparks.org"
emSubject = Me.Subject
emtextBody = Me.TextMessage
Here is a the call for sending the email
Call SendAMessage(emFrom, mailRs.Fields("EmailAddr").Value, _
emSubject, emtextBody, emAttach)
(I got the code for sending the email off the web and it works great through our mail server.)
In the above, before the call # emtextBody = Me.TextMessage is where I need to replace Me.TextMessage with the address/body of the html document. And the message box is a textBox on the ACCESS form. I can't find any control in ACCESS that takes html. I can't use the path to the html document because that generates an error. Is there a way of getting around this
If more information is required I'll be happy to supply it.
Thanks for your time.
jpl
Use something like the below code. I've included elements for attachment as well as html formatting but pretty much anything you can write in html can also be done within vba.
Sub SharePerformance()
Dim OutApp As Object
Dim OutMail As Object
Dim rng As Range
Set OutApp = CreateObject("Outlook.Application")
Set OutMail = OutApp.createitem(0)
'& "\\server\folder" &
msg1 = "Team,<br><br><b><DL>" & Range("b5").Value & "</b><br><ul><b><u>" & Range("b6").Value & "</b></u>"
msg1 = msg1 & "<DT><a HREF=C:\USER\Desktop\File1.xlsb>"
msg1 = msg1 & Range("b7").Value & "</a><br>"
msg1 = msg1 & "<b><u>" & Range("b9").Value & "</b></u></DL><br><br>"
msg1 = msg1 & "<p><img src=file://" & "C:\temp\Chart1.png" & "></p>" & "<br>"
On Error Resume Next
' Change the mail address and subject in the macro before you run it.
With OutMail
.To = Range("B1").Value
.cc = ""
.BCC = ""
.Subject = Range("B3").Value
.HTMLBody = msg1
'.Attachments.Add ActiveWorkbook.FullName
'.Attachments.Add ("C:\temp\Chart1.png")
'.Attachments.Add ("C:\temp\Chart2.png")
.display
End With
SendKeys "^{ENTER}"
On Error GoTo 0
Set OutMail = Nothing
Set OutApp = Nothing
End Sub
I can't tell what code is inside that SendAMessage function you are using but all the VBA examples I've worked with seem to work the same way with the CDO.Message object like in this MS Knowledge Base article KB286431. At some point SendAMessage is going to have a line that assigns the message object's .TextBody value to be equal to the emtextBody parameter you pass in.
One solution may be to copy your SendAMessage function into a new function SendAMessageHTML and replace the line where they are setting someMessage.TextBody = emtextBody so that you are setting someMessage.HTMLBody = emtextBody
Assuming your textbox has text along the lines of "<html><head><body></body></html>" you could modify your existing function to do a naive check like this:
if Left(UCase(emtextBody),6) = "<HTML>" then
someMessage.HTMLBody = emtextBody
else
someMessage.TextBody = emtextBody
end if

Sending Email with Late Binding Error Through VBA

I'm trying to use a late binding to email from VBA in Access 2010 and Access 2003. 2003 gives me 'Could not complete the operation. Once or more paramet values are not valid.' and 2010 gives me 'Invalid procedure call or argument.' I've done the step through and it fails at .send near the bottom. Am I setting up my binding wrong? I'm trying to do this without using Microsoft Object Library in the References.
Thanks.
'Refers to Outlook's Application object
Dim appOutlook As Object
'Refers to an Outlook email message
Dim appOutlookMsg As Object
'Refers to an Outlook email recipient
Dim appOutlookRec As Object
'Create an Outlook session in the background
Set appOutlook = CreateObject("Outlook.Application")
'Create a new empty email message
Set appOutlookMsg = appOutlook.CreateItem(olMailItem)
'Using the new, empty message...
With appOutlookMsg
strSQL = "SELECT Email FROM Employees WHERE " & sqlVar & " = True"
Set myR = CurrentDb.OpenRecordset(strSQL)
Do While Not myR.EOF
Set appOutlookRec = .Recipients.Add(myR!Email)
appOutlookRec.Type = olTo
myR.MoveNext
Loop
strSQL = "SELECT Email FROM Employees WHERE '" & user & "' = Username"
Set myR = CurrentDb.OpenRecordset(strSQL)
Set appOutlookRec = .Recipients.Add(myR!Email)
appOutlookRec.Type = olCC
.Subject = wonum
.Body = "Department: " & strDep & vbNewLine & vbNewLine & _
"Issue is at: " & strIssue & vbNewLine & vbNewLine & _
"Priority is: " & strPriority & vbNewLine & vbNewLine & _
"Complete by: " & strDate & vbNewLine & vbNewLine & _
"Description: " & strDesc
.Send
End With
Without a reference, VBA will not know about Outlook constants such as olTo and olCC. With late binding (no reference), you must supply the values for constants rather than the names of the constants.
However, since you didn't report a compile error about those constants, that suggests your code module does not include Option Explicit in its Declarations section. Trying to troubleshoot VBA code without Option Explicit is a waste of time.
Add Option Explicit, then choose Debug->Compile from the VB Editor's main menu and fix anything the compiler complains about. Resume you troubleshooting afterward.
There is an article here on sending email via Outlook using early and late binding. In the "Late Bound Conversion Checklist" at the end, the last suggestion is
Add optional arguments that have a default value
I cannot vouch for that advice because when I need to send email messages from Access I use CDO, not Outlook. Still, it sounds like it might be worth a try.

How to generate a PDF file from Access Report?

I'm having trouble trying to export an Access report to PDF format. Basically, I'm working on an old (built in 2001) Access database that uses forms as a user interface. Currently, you can send jobs from a "Jobs" form into an "Invoice" form. Once all the jobs are there, you simply click "Invoice All", specify a date and number of copies and this prints using an Access report as the template.
I've been tasked with adding a save as PDF function, but being a web designer by trade, I have very limited knowledge of Access and VB, but I do know a (very) little amount of ASP.Net and C# (how I got given this task is story for another time...)
In my mind I've approached this by creating a new PDF button on the Access form where they print the invoices. My thoughts are that I could simply duplicate the code for the printing and update to output to a PDF file instead. I can kind of get this working, but not how I'd like.
The code for the print function is below:
Private Sub cmdOpenGroupInvoice_Click()
Dim db As DAO.Database
Dim rsGetCustomerInvoice As DAO.Recordset
Dim rsInvoice As DAO.Recordset
Dim rsInvoiceAll As DAO.Recordset
Dim lngCusID As Long
Dim lngJobNo As Long
Dim iCountInvoice
Dim lngInvoiceNo As Long
Dim iNumberCopies As Integer
Dim sSQLGetInv As String
Dim sSQLInv As String
Dim datInvoiceDate As Date
sSQLGetInv = "SELECT tblJobs.JobNo,tblJobs.NetDespatchRef, tblLoads.Sales, tblLoads.PODName, tblLoads.TotalSales, tblLoads.Cost, tblLoads.Profit, tblJobs.SendToInvoice, tblJobs.Invoiced, tblJobs.MarkForHistory, tblJobs.CustomerID" & vbCrLf _
& "FROM tblJobs INNER JOIN tblLoads ON tblJobs.JobNo = tblLoads.JobNo" & vbCrLf _
& "WHERE (((tblJobs.SendToInvoice)=Yes) AND ((tblJobs.Invoiced)=No) AND ((tblJobs.MarkForHistory)=No));"
Set db = CurrentDb
Set rsGetCustomerInvoice = db.OpenRecordset(sSQLGetInv, dbOpenDynaset)
If rsGetCustomerInvoice.EOF Then
Beep
If MsgBox("There are no jobs to invoice", _
vbCritical + vbOKOnly, _
"No Jobs To Invoice") = vbOK Then
Exit Sub
End If
End If
rsGetCustomerInvoice.MoveLast
Debug.Print rsGetCustomerInvoice.RecordCount
rsGetCustomerInvoice.MoveFirst
Do Until rsGetCustomerInvoice.EOF = True
Set rsGetCustomerInvoice = db.OpenRecordset(sSQLGetInv, dbOpenDynaset)
If rsGetCustomerInvoice.EOF Then
rsGetCustomerInvoice.Close
db.Close
Set rsGetCustomerInvoice = Nothing
Set db = Nothing
DoCmd.Close acForm, "frmInvoiceDate"
Exit Sub
End If
Debug.Print rsGetCustomerInvoice.RecordCount
datInvoiceDate = CVDate(txtInvoiceDate)
lngInvoiceNo = GiveMeAnInvoiceNo()
lngCusID = rsGetCustomerInvoice.Fields!CustomerID
Call AddNewInvoice(lngInvoiceNo, datInvoiceDate, True)
Debug.Print iCountInvoice
lngJobNo = rsGetCustomerInvoice![JobNo]
Call SendThisJobToSageAll(lngCusID, datInvoiceDate, lngInvoiceNo)
Call InvoiceAll(lngCusID, lngInvoiceNo)
Dim strPODName As String
If Not IsNull(rsGetCustomerInvoice!NetDespatchRef) Then
If IsNull(rsGetCustomerInvoice![PODName]) Then
strPODName = " "
Else
strPODName = rsGetCustomerInvoice![PODName]
End If
'Call NetDesTrackingJobCompleate(rsGetCustomerInvoice![NetDespatchRef], rsGetCustomerInvoice![JobNo], strPODName)
End If
iCountInvoice = iCountInvoice - 1
'Debug.Print I
iNumberCopies = txtNumberOfCopies
Do Until iNumberCopies = 0
DoCmd.OpenReport "rptInvoice2", acViewNormal, , "[Invoice No]= " & lngInvoiceNo
iNumberCopies = iNumberCopies - 1
Loop
Form_frmInvoicing.Requery
rsGetCustomerInvoice.MoveNext
Loop
DoCmd.Close acForm, "frmInvoiceDate"
rsGetCustomerInvoice.Close
db.Close
Set rsGetCustomerInvoice = Nothing
Set db = Nothing
End Sub
With my original plan outlined above, I updated the below section to output to PDF:
Do Until iNumberCopies = 0
DoCmd.OpenReport "rptInvoice2", acViewNormal, , "[Invoice No]= " & lngInvoiceNo
DoCmd.OutputTo acOutputReport, "", acFormatPDF, MyPath & MyFilename, True
iNumberCopies = iNumberCopies - 1
Loop
Now this works and it does attempt to output a PDF file. The trouble is, it's runs the report and creates an invoice for every job in the system, rather than applying the report to JUST the jobs which are marked for invoicing.
I'm hoping this is happening because I've put the code in the wrong location, but I have a gut feeling that it's more complicated than that.
It's a bit of a long shot posting it on here, but I really appreciate any help at this point. I've also tried to keep this as short as possible, so if there's any details which aren't clear, I'll help out.
That is quite convoluted, so I think the simplest thing to do, if you do not wish to dive in and tidy up, is to modify the query that the report is based on.
Dim qdf As QueryDef
Set qdf = CurrentDb.QueryDefs("MyReportQuery")
sSQL = "SELECT Whatever FROM MyTable WHERE [Invoice No]= " & lngInvoiceNo
qdf.SQL = sSQL
DoCmd.OutputTo acOutputReport, "rptInvoice2", acFormatPDF, _
MyPath & MyFilename, True
Unless you have Access 2007 with the Save as PDF Add-on or 2010, you may be best installing say, cutePDF, and printing to the PDF printer using DoCmd.PrintOut
I asked the same question a couple of years ago on UtterAccess..
There is a free library to do exactly what you need here: http://www.lebans.com/reporttopdf.htm
My original thread at UA is here : http://www.utteraccess.com/forum/Automatically-PDF-send-t1353547.html
I successfully used the library for a couple of years in several projects, mainly to generate quotes and invoices.
Hope this helps
PG