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

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

Related

Splitting a report into separate emails with their individual reports

I am trying to send separate Employees a PDF/page of their section/report. The information is based on their EmployeeID (which is text not long number). So each person has their balance information on a page then there's a page break, and then next page shows the next person's details. With the code below, it does email each of the employees one page but it so happens to only email the first person's page to EVERYONE. Is it possible to somehow automate each week so that each user is emailed his/her individual page of the report?
Another error is that the email pop up one by one so I have to press send each time for over 200 people, and that the email seems to be sending to the email but then followed by #mailto:the email# for example email#email.com#mailto:email#email.com#
I just started Access and have been copying and scraping code off of places I have found online. Many thanks in advance, if you can assist!
Have a great day!
Private Sub cmdSendAll_Click()
Dim rsAccountNumber As DAO.Recordset
Dim strTo As Variant
Dim strSubject As String
Dim strMessageText As String
Set rsAccountNumber = CurrentDb.OpenRecordset("SELECT DISTINCT EmployeeID, [Email] FROM [queAutoUpdate]", dbOpenSnapshot)
Debug.Print strTo
With rsAccountNumber
Do Until .EOF
DoCmd.OpenReport "test", _
acViewPreview, _
WhereCondition:="EmployeeID = '" & !EmployeeID & "'", _
WindowMode:=acHidden
strTo = ![Email]
strSubject = "Updated Balance "
strMessageText = "Text Here"
DoCmd.SendObject ObjectType:=acSendReport, _
ObjectName:="test", _
OutputFormat:=acFormatPDF, _
To:=strTo, _
Subject:=strSubject, _
MESSAGETEXT:=strMessageText, _
EditMessage:=True
DoCmd.Close acReport, "Unaffirmed Report", acSaveNo
.MoveNext
Loop
.Close
End With
End Sub
Your opening a report called test and then closing another report called "Unaffirmed Report". You need to open and close the same report, in this case "test".
DoCmd.Close acReport, "test", acSaveNo. This should fix the employee data not updating, since the report remains open on the first employee.
To directly send the message you need change EditMessage:=True to EditMessage:=False.
Check the docs:
https://learn.microsoft.com/en-us/office/vba/api/access.docmd.sendobject
Also if you need to test this, set outlook in Offline mode, and run your code, check the messages in your Outbox to see if they're as expected. You can delete the messages from the Outbox to prevent them from being sent. Once you're finished with testing you can set Outlook back to Online Mode.
Regarding the email address issue, this comes automatically when using hyperlinks in your controls. You'll need to strip the extra part out with strTo = Left(![Email],InStr(![Email],"#")-1). Check your data if this will be valid for all email addresses. For a more advanced solution you can look at this post https://codekabinett.com/rdumps.php?Lang=2&targetDoc=access-hyperlink-data-type.
Code provided as reference, please see the post for the explanation.
'copied from https://codekabinett.com/rdumps.php?Lang=2&targetDoc=access-hyperlink-data-type
Public Function GetHyperlinkFullAddress(ByVal hyperlinkData As Variant, Optional ByVal removeMailto As Boolean) As Variant
Const SEPARATOR As String = "#"
Dim retVal As Variant
Dim tmpArr As Variant
If IsNull(hyperlinkData) Then
retVal = hyperlinkData
Else
If InStr(hyperlinkData, SEPARATOR) > 0 Then
' I append 4 separators at the end, so I don't have to worry about the
' lenght of the array returned by Split()
hyperlinkData = hyperlinkData & String(4, SEPARATOR)
tmpArr = Split(hyperlinkData, SEPARATOR)
If Len(tmpArr(1)) > 0 Then
retVal = tmpArr(1)
If Len(tmpArr(2)) > 0 Then
retVal = retVal & "#" & tmpArr(2)
End If
End If
Else
retVal = hyperlinkData
End If
If Left(retVal, 7) = "mailto:" Then
retVal = Mid(retVal, 8)
End If
End If
GetHyperlinkFullAddress = retVal
End Function
Consider using the MS Outlook object library to send emails. Whereas DoCmd.SendObject is a convenience handler, you control more of the process with initializing an Outlook application object and creating an Outlook email object setting all needed elements.
However, with this approach you need to first export your filtered report to PDF and then attach to email for final send. See inline comments for specific details.
Dim rsAccountNumber As DAO.Recordset
' CHECK Microsoft Outlook #.# Object Library UNDER Tools/References
Dim olApp As Outlook.Application, olEmail As Outlook.MailItem
Dim fileName As string, todayDate As String, strEmail As String
todayDate = Format(Date, "YYYY-MM-DD")
Set rsAccountNumber = CurrentDb.OpenRecordset("SELECT DISTINCT EmployeeID, [Email] FROM [queAutoUpdate]", dbOpenSnapshot)
Set olApp = New Outlook.Application
With rsAccountNumber
Do Until .EOF
' SETTING FILE NAME TO SAME PATH AS DATABASE (ADJUST AS NEEDED)
fileName = Application.CurrentProject.Path & "\Balance_Report_" & !EmployeeID & "_" & todayDate & ".pdf"
' OPEN AND EXPORT PDF TO FILE
DoCmd.OpenReport "test", acViewPreview, "EmployeeID = '" & !EmployeeID & "'"
' INTENTIONALLY LEAVE REPORT NAME BLANK FOR ABOVE FILTERED REPORT
DoCmd.OutputTo acReport, , acFormatPDF, fileName, False
DoCmd.Close acReport, "test"
' CREATE EMAIL OBJECT
strEmail = ![Email]
Set olEmail = olApp.CreateItem(olMailItem)
With olEmail
.Recipients.Add strEmail
.Subject = "Updated Balance"
.Body = "Text Here"
.Attachments.Add fileName ' ATTACH PDF REPORT
.Send ' SEND WITHOUT DISPLAY TO SCREEN
End With
Set olEmail = Nothing
.MoveNext
Loop
.Close
End With
MsgBox "All emails successfully sent!", vbInformation, "EMAIL STATUS"
Set rsAccountNumber = Nothing: Set olApp = Nothing

Access Get subfolder of shared folder meetings

I have the code below that should let me retrieve the meetings from a shared sub calendar, but it doesn't work.
If I only try to access the main shared calendar it works perfect, but not for the sub calendars..
could someone point me to the right way?
Public Sub getCalendarData(calendar_name As String, sDate As Date, eDate As Date, Optional recurItem As Boolean = True)
On Error GoTo ErrorHandler
Dim oOL As Outlook.Application
Dim oNS As Outlook.Folder
Dim oAppointments As Outlook.AppointmentItem
Dim oAppointmentItem As Outlook.AppointmentItem
Dim strFilter As String
Dim ItemsCal As Outlook.Items
Dim olFolder As Outlook.Folder
Dim fldCalendar As Outlook.Folder
Dim iCalendar As Integer
Dim nmsNameSpace As Outlook.Namespace
Dim objDummy As Outlook.MailItem
Dim objRecip As Outlook.Recipient
'Set objects
Set oOL = CreateObject("Outlook.Application")
Set nmsNameSpace = oOL.GetNamespace("MAPI")
Set objDummy = oOL.CreateItem(olMailItem)
Set objRecip = nmsNameSpace.CreateRecipient("shared calendar name")
objRecip.Resolve
'Set filter to grab items by date range
strFilter = "[Start] >= " _
& "'" & sDate & "'" _
& " AND [End] <= " _
& "'" & eDate & "'"
With ItemsCal
.Sort "[Start]"
.IncludeRecurrences = recurItem
End With
If objRecip.Resolved Then
On Error Resume Next
Set fldCalendar = nmsNameSpace.GetSharedDefaultFolder(objRecip, olFolderCalendar).Folders("sub_calendar_name")
If Not fldCalendar Is Nothing Then
Set ItemsCal = fldCalendar.Items
If Not ItemsCal Is Nothing Then
For Each oAppointmentItem In ItemsCal.Restrict(strFilter)
Set objItem = oAppointmentItem
With oAppointmentItem
iCalendar = getSegmentIDByName(calendar_name)
meeting_id = insertAppointment(iCalendar, .Start, .End, scrubData(.Subject), scrubData(.Location), Format(.Start, "Long Time"), .duration, .Body)
Call GetAttendeeList(meeting_id, objItem, .Recipients)
End With
Next
End If
End If
End If
'Garbage cleanup
Set oAppointmentItem = Nothing
Set oAppoinments = Nothing
Set oNS = Nothing
Set oOL = Nothing
Exit Sub
ErrorHandler:
'MsgBox "Error: " & Err & " | " & Error(Err)
'Whenever error occurs, skip to next
Resume Next
End Sub
The problem is that fldCalendar is always returning nothing and I don't know what is wrong..
Thank you!
Keep in mind that in the cached mode when you are accessing a default folder from another mailbox, you are not accessing the whole mailbox - the folder (but not its subfolders) is cached in your primary OST file.
You can add the whole mailbox as a delegate store (Advanced tab of the Exchange account properties dialog box) and then drill down to that folder from Store.RootFolder (where Store is retrieved from the Namespace.Stores collection).
If using Redemption is an option (I am its author), its version of RDOSession.GetSharedDefaultFolder (or RDOSession.GetSharedMailbox) returns a live folder (RDOFolder), not its cached version, so you will be able to access the subfolders.

Sending an email from Access using a different Outlook email address

I am trying to send a fax from Outlook using a different Outlook address than mine which is the one that it defaults to. Below is my code.
Thank you.
Private Sub FaxDoctor() ' Faxes the doctor with the letter
On Error GoTo Error_Handler
Dim fso
Dim olApp As Object
' Dim olApp As Outlook.Application
Dim olNS As Outlook.NameSpace
Dim olfolder As Outlook.MAPIFolder
Dim olMailItem As Outlook.MailItem
Set fso = CreateObject("Scripting.FileSystemObject")
If fso.FileExists("\\pna434h0360\PharmServ\Output\" & Me!ID & ".pdf") Then ' If the filename is found
Set olApp = CreateObject("Outlook.Application")
Set olNS = olApp.GetNamespace("MAPI")
Set olfolder = olNS.GetDefaultFolder(olFolderInbox)
Set olMailItem = olfolder.Items.Add("IPM.Note")
olMailItem.display
With olMailItem
.Subject = " "
.To = "[fax:" & "Dr. " & Me.[Prescriber First Name] & " " & Me.[Prescriber Last Name] & "#" & 1 & Me!Fax & "]" ' Must be formatted exactly to be sent as a fax
'.Body = "This is the body text for the fax cover page" ' Inserts the body text
.Attachments.Add "\\pna434h0360\PharmServ\Output\" & Me!ID & ".pdf" ' attaches the letter to the e-mail/fax
'.SendUsingAccount = olNS.Accounts.Item(2) 'Try this to change email accounts
End With
Set olMailItem = Nothing
Set olfolder = Nothing
Set olNS = Nothing
Set olApp = Nothing
Else
GoTo Error_Handler
End If
Exit_Procedure:
On Error Resume Next
Exit Sub
Error_Handler:
MsgBox ("No Letter found" & vbCrLf & "If you are certain the letter is saved with the correct filename then close down Outlook and try again.") ' This often crashes because the letter is not found or because outlook has crashed. In which case every Outlook process should be closed and Outlook should be restarted.
Exit Sub
End Sub
You can change the outlook account by using the 'SendUsingAccount' property of the mail item. This needs to be set to an account object.
You can set the account for a given name using something like this where 'AccountName' is the address you're sending from.
Dim olAcc as Outlook.Account
For Each olAcc In Outlook.Session.Accounts
If outAcc.UserName = 'AccountName' Then
olMailItem.SendUsingAccount = outAcc
Exit For
End If
Next
Try using ".SendOnBehalfOfName"
I found this function online, so just follow its lead:
Function SendEmail()
Dim Application As Outlook.Application
Dim NameSpace As Outlook.NameSpace
Dim SafeItem, oItem ' Redemption
Set Application = CreateObject("Outlook.Application")
Set NameSpace = Application.GetNamespace("MAPI")
NameSpace.Logon
Set SafeItem = CreateObject("Redemption.SafeMailItem") 'Create an instance of Redemption.SafeMailItem
Set oItem = Application.CreateItem(0) 'Create a new message
SafeItem.Item = oItem 'set Item property
SafeItem.Recipients.Add "customer#ispprovider.com"
SafeItem.Recipients.ResolveAll
SafeItem.Subject = "Testing Redemption"
SafeItem.SendOnBehalfOfName = "Invoices#companyname.com"
SafeItem.Send
End Function

Getting Access to send emails to dynamic addresses

This is in Access 2010 and I have virtually no experience or familiarity with VBA.
In my form (frmEmailLookup), I have combo boxes and list boxes and a subform set up so that when the user selects a building from cmbBuilding the remainder of the form populates with the data on that building, including the contact emails for up to 4 people in the building (lstBuildingRepEmail1, lstBuildingRepEmail2, lstBuildingRepEmail3, lstBuildingRepEmail4). I need a button (butEmailRecords) to generate an email with the query from the subform (qryBuildingAreaLookup) as an attachment. I can set up a macro that will something close, but it doesn't allow for dynamic email addresses. I don't want my users to have to go that far into the program to make updates.
Any help is appreciated and I know I'm asking for a lot of code writing help.
Here's what I've tried:
Option Compare Database
Private Sub butEmailRecords_Click()
Dim outputFileName As String
outputFileName = CurrentProject.Path & "\BuildingInventory" & ".xlsx"
DoCmd.TransferSpreadsheet acExport, acSpreadsheetTypeExcel9, "qryBuildingAreaLookup", outputFileName, True
On Error GoTo Error_Handler
Dim objOutlook As Outlook.Application
Dim objEmail As Outlook.MailItem
Set objOutlook = CreateObject("Outlook.application")
Set objEmail = objOutlook.CreateItem(olMailItem)
Dim rs As DAO.Recordset
Set rs = CurrentDb.OpenRecordset("qryBuildinAreaLookup")
With rs
With objEmail
.To = tblBuilding.BuildingRep1
.To = tblBuilding.BuildingRep2
.To = tblBuilding.BuildingRep3
.To = tblBuilding.BuildingRep4
.Subject = "Look at this sample attachment"
.body = "The body doesn't matter, just the attachment"
.Attachments.Add "L:\Administration\FacilityInventoryDatabase\BuildingInventory.xls x"
.Send
'.ReadReceiptRequested
End With
Exit_Here:
Set objOutlook = Nothing
Exit Sub
Error_Handler:
MsgBox Err & ": " & Err.Description
Resume Exit_Here
End Sub
Here is the basics of what I use:
'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
'SQL statement to grab emails
Set recordset = currentdb.openrecordset('SQL statement')
Do While Not recorset.EOF
Set appOutlookRec = .Recipients.Add(recordset.Email)
appOutlookRec.Type = olTo
recordset.MoveNext
Loop
.Subject = ....
.Body = ....
.Send
End With
and that's the basics of what I use. I'm a beginner so this may not be the best way, but it should be a start. (I also had to add Microsoft Oulook in the reference library.)
I use CDO objects to send messages because I prefer not to rely on Outlook (for anything).
There is quite a comprehensive article on using CDO to send mail (including downloadable VBA code) here:
http://www.cpearson.com/excel/Email.aspx

Sending Outlook email using Access VBA

This code is working in another Access db.
I just copy pasted the code but there is an error in the first line.
Public Function sendEmailOutlook()
Dim objOutlook As Outlook.Application
Dim objOutlookMsg As Outlook.MailItem
Dim objOutlookRecip As Outlook.Recipient
Dim objOutlookAttach As Outlook.Attachment
On Error GoTo ErrHandler:
' Create the Outlook session.
Set objOutlook = CreateObject("Outlook.Application")
' Create the message.
Set objOutlookMsg = objOutlook.CreateItem(olMailItem)
With objOutlookMsg
' Add the To recipient(s) to the message.
Set objOutlookRecip = .Recipients.Add("sads")
'Set objOutlookRecip = .Recipients.Add("niticin#gmail.com")
objOutlookRecip.Type = olTo
' Set the Subject, Body, and Importance of the message.
.Subject = "This is an automatic confirmation"
.Body = "This is a confirmation of the" & Form_Booking.Event_Name.Value & vbCrLf & _
"Client: " & Form_Booking.FirstName.Value & vbCrLf & vbCrLf & _
"Start Time: " & Form_Booking.Actual_Start_Time.Value
.Importance = olImportanceHigh 'High importance
.Save
.Send
End With
'Set objOutlookMsg = Nothing
Set objOutlook = Nothing
Exit Function
ErrHandler:
MsgBox ("Make sure your Outlook is active and configured!")
End Function
Error on line
Dim objOutlook As Outlook.Application
compiler : user defined type not defined.
You're using early binding, so in the VBA Editor you need to click Tools -> References & tick Microsoft Outlook ?? Object Library in order to expose Outlook's object model to your code.