send email with VBA with no user interaction with email client - email

I'm trying to get this code to send the attachment via email. But their will be several hundred attachments, so i don't want the user to need to interact with the email client. Any suggestions would be greatly appreciated.
Private Sub CreateReports_Click()
Dim x As String
Dim y As String
Dim StrSQL As String
Dim stWhereStr As String 'Where Condition'
Dim stSection As String 'Selection from drop down list
Dim stfile As String
Dim stDocName As String
Dim StrEmail As String
StrSQL = "SELECT DISTINCTROW [OPDA ISSR- Courts Users by District/Cir].[Sup], [OPDA ISSR- Courts Users by District/Cir].SupEmail " & _
"FROM [OPDA ISSR- Courts Users by District/Cir];"
y = Year(Date)
Dim db As DAO.Database
Dim rst As DAO.Recordset
Set db = CurrentDb
Dim qdTemp As DAO.QueryDef
Set qdTemp = db.CreateQueryDef("", StrSQL)
Set rst = qdTemp.OpenRecordset()
If rst.EOF And rst.BOF Then
MsgBox "No data available for the Ledger Process routine."
Else
Debug.Print rst.Fields.Count
rst.MoveFirst
Do While Not rst.EOF
x = rst![Sup]
StrEmail = rst![Supemail]
stDocName = "Courts - ISSR Recertification Report"
stWhereStr = "[OPDA ISSR- Courts Users by District/Cir].[SUP]= '" & x & "'"
stfile = "P:\DFI\FIB\Access Tables\FibCustomers\ISSR Reports\Courts\" & x & " - " & y & " FedInvest InvestOne Recertification.pdf"
DoCmd.OpenReport stDocName, acPreview, , stWhereStr
DoCmd.SendObject acSendReport, stDocName, acFormatPDF, StrEmail, , , "My Subject here", "your report"
DoCmd.OutputTo acOutputReport, stDocName, acFormatPDF, stfile
DoCmd.Close acReport, stDocName
rst.MoveNext
Loop
End If
rst.Close
Set rst = Nothing
End Sub

You could either use your local email client's API and open a hidden instance to create and send emails (e.g. Outlook, Lotus Notes) or you could use the CDO object.
http://www.rondebruin.nl/win/s1/cdo.htm
Even though the above example is in Excel, the code works great. The only thing you will have to make sure if you're using the CDO object is if the necessary ports are open. Also check the related threads to this question, tons of valid information if you want to go with a specific email client.

The best way to send unattended emails is to use SMTP. Bypassing the MAPI security prompts is not a good idea.
Our Total Access Emailer addin program uses SMTP so you can broadcast a large volume of emails for your users. Total Access Emailer lets you send personalized emails to everyone on your list and embed fields from your records in the message and subject. It can also attach Access reports as PDF files filtered for each recipient so that each person only sees their data. No programming is required with its Wizard interface. A VBA library is available if you want to automate it. More info here: http://www.fmsinc.com/MicrosoftAccess/Email.asp
A free trial is available: http://www.fmsinc.com/MicrosoftAccess/Email/free-trial.html

Related

Access pass-through query with parameters not updating with prompted parameters

An Access pass-through query works when using the default parameters. When used in an Access report, the prompts that are used returns records based on the default parameters in the ptq and not the answered prompts. Default data is being returned.
I have a SQL Server based stored procedure that works, uspWorkCentreReport, that uses #TheDate DATE, #WC VARCHAR(15), #Shift INT for parameters and returns, through a SELECT statement, these columns:
[JOB NUMBER], [REL #], [JOB NAME], QTY.
Here's the ALTER line of the stored procedure code:
ALTER PROCEDURE [dbo].[uspWorkCentreReport]
#TheDate DATE,
#WC VARCHAR(15),
#Shift INT
The Access pass-through query, ptq_uspWorkCentreReport, passes these default parameters '2019-05-30','PCOT',1 and uses a DSN-less ODBC connection that works to return default data. I forgot to try but I think it will return correct data with whatever default parameters I use to replace '2019-05-30','PCOT',1. EDIT - I tried it this morning and indeed any appropriate replacement parameters return the appropriate associated records. Here's the ptq's one line:
exec uspWorkCentreReport '2019-05-30','PCOT',1
I provide the ptq with default parameters based on Albert D. Kallal's SO reply.
I use an Access select query, qry_ptq_uspWorkCentreReport, to receive [JOB NUMBER],[REL #],[JOB NAME],QTY and pass the parameters TheDate, set to Date With Time, WC, set to Short Text, and Shift, set to Integer.
qry_ptq_uspWorkCentreReport uses the pass-through query. The parameters are set using Access' Parameters applet and not within the query fields. Running this select query prompts for the 3 parameters but only returns data based on the default parameters set in the ptq's one line. I did not think to look at the Access SQL statement but will do so when I get to work tomorrow morning. EDIT - Here's the SQL statement for qry_ptq_uspWorkCentreReport:
PARAMETERS TheDate DateTime, WC Text ( 255 ), Shift Short;
SELECT ptq_uspWorkCentreReport.[JOB NUMBER], ptq_uspWorkCentreReport.[REL #], ptq_uspWorkCentreReport.[JOB NAME], ptq_uspWorkCentreReport.QTY
FROM ptq_uspWorkCentreReport;
Of course the above three functions culminate in an Access report, rpt_qry_ptq_WorkCentreReport to make the records human readable.
I have used the same scenario for another report the takes From and To dates as parameters. When that report runs, the prompts take the dates and return records based on those dates and not the dates in the ptq. Here's that ptq:
exec uspMergeAandPJobs '2018-01-01','2019-01-01'
Indeed, I tried using
exec uspMergeAandPJobs '',''
And the report returns 0 records!
Not sure what I am missing and would appreciate any feedback. TIA.
I tried the following with the help of a tutor:
Sub Report_Load()
Dim strFromDate As String
Dim strToDate As String
Dim strWC As String
Dim intShift As Integer
Dim strSQL As String
strFromDate = InputBox("From Date and Time: ")
strToDate = InputBox("Enter To Date and Time: ")
strWC = InputBox("Enter Work Center: ")
intShift = InputBox("Enter Shift: ")
Dim qdf As DAO.QueryDef, rst As DAO.Recordset
Set qdf = CurrentDb.CreateQueryDef("")
qdf.SQL = "exec dbo.uspWorkCentreReport " & "'" & strFromDate & "', " & "'" & strToDate & "', " & "'" & strWC & "', " & intShift & ";"
qdf.Connect = "ODBC;DRIVER=ODBC Driver 13 for SQL Server;SERVER=OURS\NTSQL;Trusted_Connection=Yes;DATABASE=TablesCoE;ApplicationIntent=READONLY;"
qdf.ReturnsRecords = True
Set rst = qdf.OpenRecordset
rst.Close
Set rst = Nothing
Set qdf = Nothing
End Sub
After the prompts VBA spits up a Run-Time error 3129 - Invalid SQL statement; expected 'DELETE', 'INSERT', 'PROCEDURE', 'SELECT', or 'UPDATE'. Neither of us were able to determine what was causing the error. In VBA the "qdf.SQL..." line is highlighted in yellow.
EDIT - Adding stored proc's SQL code:
ALTER PROCEDURE [dbo].[uspWorkCentreReport_TEST] #FromDate DATETIME,#ToDate DATETIME,#WC VARCHAR(15),#Shift INT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
-- Build table variable SumTable structure
DECLARE #SumTable TABLE(matl_nbr VARCHAR(60),QTY DECIMAL(4,0),matl_dsc VARCHAR(50))
-- P jobs and their summed WorkCentre traversals using crosstab - each traversal is added up
INSERT INTO #SumTable(matl_nbr,matl_dsc,QTY)
SELECT SRC1.matl_nbr,SRC1.matl_dsc,
SUM(CASE WHEN SRC1.locn_to = #WC THEN 1 ELSE 0 END) AS QTY
FROM
(
SELECT matl_nbr,matl_dsc,locn_to
FROM mtrk_CompanyE.dbo.trxn_hstd th
WHERE (last_upd >= #FromDate AND last_upd <= #ToDate) AND
locn_to = #WC
)SRC1
GROUP BY matl_nbr,matl_dsc
-- These updates take all the summed WorkCentre (locn_to) columns and turn each into "1" for later summing
UPDATE #SumTable
SET QTY = 1
WHERE QTY >1
-- Shortening the material number from 123456_00_00_R1_00 to 1234560
UPDATE #SumTable
SET matl_nbr = LEFT(matl_nbr,6) + right(LEFT(matl_nbr,9),1)
SELECT LEFT(A.matl_nbr,6)[JOB NUMBER],SUBSTRING(A.matl_nbr,7,1)[REL #],matl_dsc AS [JOB NAME],QTY
FROM (SELECT matl_nbr,matl_dsc,
SUM(CASE WHEN QTY = 1 THEN 1 ELSE NULL END) AS QTY
FROM #SumTable
GROUP BY matl_nbr,matl_dsc)A
ORDER BY QTY DESC;
END
EDIT - Finished sub:
Private Sub Report_Open(Cancel As Integer)
Dim strFromDate As String
Dim strToDate As String
Dim strWC As String
Dim intShift As Integer
Dim strSQL As String
strFromDate = InputBox("Enter From Date and Time: ")
strToDate = InputBox("Enter To Date and Time: ")
strWC = InputBox("Enter Work Center: ")
intShift = InputBox("Enter Shift: ")
strSQL = "exec dbo.uspWorkCentreReport_TEST " & "'" & strFromDate & "', " & "'" & strToDate & "', " & "'" & strWC & "', " & intShift & ";"
CurrentDb.QueryDefs("ptq_uspWorkCentreReport").SQL = strSQL
DoCmd.OpenReport "rpt_qry_ptq_uspWorkCentreReport", acViewReport
Me.lblFromDate.Caption = strFromDate
Me.lblToDate.Caption = strToDate
Me.lblWC.Caption = strWC
Me.lblShift.Caption = intShift
End Sub
Your Access query has parameters:
PARAMETERS TheDate DateTime, WC Text ( 255 ), Shift Short;
and since they are defined in the query definition, Access asks for them when opening/running the query.
But these parameters are never used!
There is no way for Access to pass these parameters into the pass-through query that is the basis of the Access query. Again, a PT query is nothing more than a Connect string and a constant SQL string.
So when you run the Access query, it will always run the saved contents of the PT query, i.e.
exec uspWorkCentreReport '2019-05-30','PCOT',1
The parameters you entered are ignored.
What you need to do (as outlined in the answer you refer to):
create a form to collect the parameter values
dynamically create the SQL string for the PT query with VBA
assign that SQL to the PT query:
CurrentDb.QueryDefs("ptq_uspWorkCentreReport").SQL = strSql
(it is automatically saved)
and then you can run the report based on the Access query - or better: directly use the PT query as record source for the report.
Remove the parameters from the Access query, they are of no use for your situation. Or remove the query entirely, unless you need it to join the PT query with something else.
Edit for above edit:
If you get a runtime error, there is probably a syntax error in your .Sql. Build the SQL string in a variable, do Debug.Print strSql, and run that string in SSMS. You may need to change date formatting (depending on your locale settings).
Also: See my 3rd bullet. Defining a temporary querydef and opening a recordset doesn't work for a report. You must assign the .Sql of the existing query that is the record source of the report.
Addendum: if you need to create a new query, first set .Connect, and then .Sql, so Access knows it's a Pass-Through query.
Access SQL doesn't know exec.
Edit 2
You have an existing, working PT query ptq_uspWorkCentreReport, which returns records for one set of parameters, e.g.
exec uspWorkCentreReport '2019-05-30','PCOT',1
Use this query as record source for your report.
To run the report with different parameters, you must modify the query's SQL. You can do this manually in query design view, or with VBA.
I think Report_Load() is too late for modifying its record source (the PT query). Run the following sub, then open the Report.
Sub SetUspParameters()
Dim strFromDate As String
Dim strToDate As String
Dim strWC As String
Dim intShift As Integer
Dim strSQL As String
strFromDate = InputBox("From Date and Time: ")
strToDate = InputBox("Enter To Date and Time: ")
strWC = InputBox("Enter Work Center: ")
intShift = InputBox("Enter Shift: ")
strSQL = "exec dbo.uspWorkCentreReport " & "'" & strFromDate & "', " & "'" & strToDate & "', " & "'" & strWC & "', " & intShift & ";"
Debug.Print strSQL
' This line is all that's needed to modify the PT query
CurrentDb.QueryDefs("ptq_uspWorkCentreReport").SQL = strSQL
End Sub
In practice, you don't want to use 4 x InputBox, but a form.

how to use a form to navigate to specific query based on what is entered on the msgbox?

So I have a Access database with a table transaction.
On the table there is a column called profit filtered by month.
I have already made a few queries to calculate the total profit on monthly basis (eg. Jun,July,Aug)
So is it possible to create a form with a pop-up message box, and by enter a month number on the box and click, it will lead to a specific query?
I think it is a good idea but I know little about ACCESS programing so any comment are much appriciated!
You can use VBA's InputBox function to create the pop-up. If your queries already exist in the database, you could then use the results of that function to determine which query to open. For example:
Public Sub OpenExistingQuery()
Dim intMonth As Integer
intMonth = InputBox("Please enter a month number:", "Enter Month Number")
DoCmd.OpenQuery "qryMonth" & intMonth, acViewNormal
End Sub
Alternatively, you could use the results of the InputBox function to dynamically build a query, and then open it:
Public Sub OpenDynamicQuery()
Const strQueryName As String = "qryDynamicMonth"
Dim db As DAO.Database: Set db = CurrentDb
Dim qdf As DAO.QueryDef
Dim intMonth As Integer
intMonth = InputBox("Please enter a month number:", "Enter Month Number")
On Error Resume Next
DoCmd.Close acQuery, strQueryName, acSaveNo
DoCmd.DeleteObject acQuery, strQueryName
On Error GoTo 0
Set qdf = db.CreateQueryDef(strQueryName)
qdf.SQL = "SELECT * FROM your_table_name WHERE your_monthnumber_column = " & intMonth
qdf.Close
DoCmd.OpenQuery strQueryName, acViewNormal
Set qdf = Nothing
Set db = Nothing
End Sub
Please note that the above functions are of the "quick-and-dirty" variety. They really need better error handling, sanitation of user input, etc. But hopefully you get the idea, and can take care of that on your own.

Trying to grab multiple fiedld from querydef and transfer to default email

I have been working with a database and received help getting the correct function to occur in that the code is working with a query and then looping through each report group (by name) and populating the fields of a report and saving the report by individual name. The last part of this which I have been struggling with. One of the fields in the recordset is Sup_Email, I’m trying to pass the report for sup with the email address in the above field to my default email client. I can’t figure how to isolate the second variable, keep it together with the right report and pass them both to email. Any help would be greatly appreciated.
Private Sub CreateReports_Click()
Dim x As String
Dim y As String
Dim z As String
Dim StrSQL
Dim StrEmail
Dim stWhereStr As String 'Where Condition'
Dim stSection As String 'Selection from drop down list
Dim stfile As String
StrSQL = "SELECT distinct[Sup] FROM ([OPDA ISSR- Courts Users by District/Cir])"
StrEmail = "SELECT [Sup_email] FROM ([OPDA ISSR- Courts Users by District/Cir])"
y = Year(date)
Dim db As DAO.Database
Dim rst As DAO.Recordset
Set db = CurrentDb
Dim qdTemp As DAO.QueryDef
Set qdTemp = db.CreateQueryDef("", StrSQL)
Set rst = qdTemp.OpenRecordset()
If rst.EOF And rst.BOF Then
MsgBox "No data available for the Ledger Process routine."
Else
rst.MoveFirst
Do While Not rst.EOF
x = rst![Sup]
z = rst![Sup_email]
stDocName = "Courts - ISSR Recertification Report"
stWhereStr = "[OPDA ISSR- Courts Users by District/Cir].[SUP]= '" & x & "'"
stfile = "P:\DFI\FIB\Access Tables\FibCustomers\ISSR Reports\Courts\" & x & " - " & y & " FedInvest InvestOne Recertification.pdf"
DoCmd.OpenReport stDocName, acPreview, , stWhereStr
DoCmd.OutputTo acOutputReport, stDocName, acFormatPDF, stfile
DoCmd.Close acReport, stDocName
rst.MoveNext
Loop
End If
rst.Close
Set rst = Nothing
End Sub
Each Sup has only one email address. The way it is setup is that a query (the OPDA ISSR- Courts Users by District/Cir query from above) pulls the first and last name of the supervisor and concatenates it into Sup, it also has their phone and email address (Sup_email), then has the employee, their accounts and access level, this information all applies to each field of the form. The direction I was sent yesterday created a query recordset (it's was continuing to loop). I tried then to add the field for email, and it's all gone awry since.
I have modified your code so that it uses the email address from the table and will create the report, then send.
Private Sub CreateReports_Click()
Dim x As String
Dim y As String
Dim StrSQL As String
Dim stWhereStr As String 'Where Condition'
Dim stSection As String 'Selection from drop down list
Dim stfile As String
Dim stDocName As String
Dim StrEmail As String
StrSQL = "SELECT DISTINCTROW [OPDA ISSR- Courts Users by District/Cir].[Sup], [OPDA ISSR- Courts Users by District/Cir].SupEmail " & _
"FROM [OPDA ISSR- Courts Users by District/Cir];"
y = Year(Date)
Dim db As DAO.Database
Dim rst As DAO.Recordset
Set db = CurrentDb
Dim qdTemp As DAO.QueryDef
Set qdTemp = db.CreateQueryDef("", StrSQL)
Set rst = qdTemp.OpenRecordset()
If rst.EOF And rst.BOF Then
MsgBox "No data available for the Ledger Process routine."
Else
Debug.Print rst.Fields.Count
rst.MoveFirst
Do While Not rst.EOF
x = rst![Sup]
StrEmail = rst![Supemail]
stDocName = "Courts - ISSR Recertification Report"
stWhereStr = "[OPDA ISSR- Courts Users by District/Cir].[SUP]= '" & x & "'"
stfile = "P:\DFI\FIB\Access Tables\FibCustomers\ISSR Reports\Courts\" & x & " - " & y & " FedInvest InvestOne Recertification.pdf"
DoCmd.OpenReport stDocName, acPreview, , stWhereStr
DoCmd.SendObject acSendReport, stDocName, acFormatPDF, StrEmail, , , "My Subject here", "your report"
DoCmd.OutputTo acOutputReport, stDocName, acFormatPDF, stfile
DoCmd.Close acReport, stDocName
rst.MoveNext
Loop
End If
rst.Close
Set rst = Nothing
End Sub

CDO Email Automation

I have a MS Access 2010 db that I want to send emails from automatically. I have the query set up but am getting stuck with the CDO VBA. They query is called 'qryEmails' and contains the following 4 fields:
ReturnCode, SalesOrderNumber, Name, EmailAddress
How do I get Access to:
Loop through each record and send an email to each email address listed
In each email, have a message that will contain reference to the
first 3 fields, so each message appears personalised
Have a dynamic subject, so the ReturnCode field is in each subject
I have been trying small steps at first, so far I am receiving 100's of emails to the same address. Here is my code (I have used XXX where I do not want to disclose info):
Dim rst As ADODB.Recordset
Dim strSQL As String
Dim strEmail As String
Set rst = New ADODB.Recordset
'
strSQL = "[qryEmails]" 'source of recordset
rst.Open strSQL, CurrentProject.Connection, adOpenKeyset, adLockOptimistic
'
Do While Not rst.EOF
strEmail = rst.Fields("EmailAddress")
Set objMessage = CreateObject("CDO.Message")
objMessage.Subject = "Your refund is:" '
objMessage.FROM = """SENDER"" <XXX#somewhere.com>"
objMessage.To = rst.Fields("EmailAddress")
objMessage.TextBody = objMessage.TextBody & rst(1)
'==Add fields to email body
'Do While strEmail = rst.Fields("EmailAddress")
'rst.MoveNext
'If rst.EOF Then Exit Do
'Loop
' ========= SMTP server configuration
objMessage.Configuration.Fields.Item _
("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2
'Name or IP of Remote SMTP Server
objMessage.Configuration.Fields.Item _
("http://schemas.microsoft.com/cdo/configuration/smtpserver") = "XXX"
'Server port (typically 25)
objMessage.Configuration.Fields.Item _
("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = 25
objMessage.Configuration.Fields.Update
'==End remote SMTP server configuration section==
'Send email
objMessage.Send
'Clear variable for next loop
Set objMessage = Nothing
Loop
rst.Close
Set rst = Nothing
Any idea why this is sending 100's of emails? The query result so far is only returning two addresses for testing purposes.
Within the loop, the recordset remains on the same row. And since the recordset row does not change, it never reaches rst.EOF
That code includes a disabled line for MoveNext. Uncomment that line. And you probably want to position it just before the Loop statement.
Do While Not rst.EOF
' do everything you need for current record,
' then move to the next record ...
rst.MoveNext
Loop

Pass an email address to the SendObject method in VBA

I would like to take the email address from my table 'GetContact_TempTbl" and send the report to that email address. This email will change according the company that recieves. I currently pull the related email address and store it in the temporary table. I currently get the Object Required error.
Many thanks in advace for the advice.
Dim db As Database
Dim rs As Recordset
Dim stRecipients As String
Dim stDocName As String
Set db = CurrentDb()
Set rs = db.OpenRecordset("GetContact_TempTbl")
Set stRecipients = rs.Fields("Contact_Email")
stDocName = "License CODs"
stRecipietns = stRecipients
DoCmd.SendObject acReport, stDocName, acFormatPDF, stRecipients, , , "Thank You for your purchase"
If your recordset holds one row for each recipient you want to email, walk the recordset to gather them instead of reading only the recipient from the first row.
Const stDocName As String = "License CODs"
Dim db As DAO.database
Dim rs As DAO.Recordset
Dim stRecipients As String
Set db = CurrentDb()
Set rs = db.OpenRecordset("GetContact_TempTbl")
With rs
Do While Not .EOF
stRecipients = stRecipients & ";" & !Contact_Email
.MoveNext
Loop
.Close
End With
If Len(stRecipients) > 0 Then
' discard leading ";"
stRecipients = Mid(stRecipients, 2)
DoCmd.SendObject acReport, stDocName, acFormatPDF, _
stRecipients, , , "Thank You for your purchase"
Else
MsgBox "No recipients to email!"
End If
Set rs = Nothing
Set db = Nothing
However, if my interpretation was incorrect, and the recordset always contains a single row with just one Contact_Email, you don't even need a recordset. You can simply retrieve the Contact_Email with DLookup.
stRecipients = Nz(DLookup("Contact_Email", "GetContact_TempTbl"), "")
You should only use set with an object, not a string:
Dim db As Database
Dim rs As Recordset
Dim stRecipients As String
Dim stDocName As String
Set db = CurrentDb()
Set rs = db.OpenRecordset("GetContact_TempTbl")
''This is not a field object, it is a string
stRecipients = rs.Fields("Contact_Email")
stDocName = "License CODs"
stRecipietns = stRecipients
DoCmd.SendObject acReport, stDocName, acFormatPDF, _
stRecipients, , , "Thank You for your purchase"
It may be possible to make this easier if you say how you create the temporary table.