So I have a function that allows the user to email an updated picture for an asset which works fine and good except if the user closes the email before sending. I have an error handler set up but it doesn't seem to capture the error. Here is my function code:
Function Email()
Globals.Logging "Opened Email for updating picture"
On Error GoTo ErrorHandler:
Dim strTagNumber As String
strTagNumber = Me.txtTagNumber.Value
Dim varName As Variant
Dim varCC As Variant
Dim varSubject As Variant
Dim varBody As Variant
varName = "myAnon#email.test"
varCC = ""
varSubject = "Updated Picture for Asset Number " & strTagNumber
varBody = "Sent by MS Access"
DoCmd.SendObject , , , varName, varCC, , varSubject, varBody, True, False
Globals.Logging "Sent Email"
Cleanup:
varName = Nothing
varCC = Nothing
varSubject = Nothing
varBody = Nothing
Exit Function
ErrorHandler:
Select Case Err.Number
Case 2501
MsgBox "Email message was Cancelled."
Globals.Logging "Canceled Email"
Case Else
MsgBox Err.Number & ": " & Err.Description
Globals.Logging "Email Error " & Err.Number & ": " & Err.Description
End Select
Resume Cleanup
End Function
Any help would be appreciated. Thank you in advance.
As described in online documentation, DoCmd.SendObjects
... uses the Mail Applications Programming Interface (MAPI)
In other words, Access (or Excel) does not actually have its own email capability. It is dependent upon a properly installed and configured MAPI email client. Unless you have purposefully installed and setup another default email client on Windows, the default is likely Outlook if you have it installed with MS Office. Windows email clients have changed with the many version of Windows, but the default might also be a simple Windows email client.
It is very likely that the MAPI client could be showing the error message, then not actually throwing/raising the error before it returns program flow back to the VBA module which initiated the call.
I recall being aware at some point of an Outlook setting that dictated certain behavior for MAPI and/or COM Automation interfaces, whether it showed errors or not. I usually would not throw out such wishy-washy info on Stack Overflow before verifying, but from what I see of the discussion around this issue, nobody really addresses this aspect of SendObjects.
Besides using Automation to send email via Outlook as other have suggested, you could inspect the Windows default email client settings. Perhaps test another email client to see if you get different results.
Tested on Access 2016. The error is captured and I can see the message box saying "Email message was Cancelled.".
Maybe you can try to use Outlook object for sending the email too.
Related
I have an error log that logs in the access table whenever a runtime error occurs for a user in the error trapper, and a particular error seems to occur for 10 random users, every hour at least.
This error appears to occur completely at random, on a random module with the Set ActiveForm code, with random users at random intervals. As far as I can see, there is no pattern between the users.
2475 - "You entered an expression that requires a form to be the active window".
This appears to occur in any of the modules that contain any of the setting of a form. I am using the following lines:
Dim af as Object
Set af = Screen.ActiveForm
I have tried using alternatives, such as declaring it as Form, and also tried the below:
Dim sstatus as String
Dim ps as String
If DLookup("[TM_UserType]", "[SD_Teams]", "[TM_username]= '" & usernm & "'") = "adj" Then
sstatus = "adj"
Else
sstatus = "tm"
End If
ps = "frmProdSubmit_" & sstatus
Then referencing the form this way:
Forms(ps).cmbTeam.Value = ""
But this still causes the same issue, even removing the ActiveForm part.
The last thing to mention (as I believe they could be factors) is that the front end is accessed through a shortcut, which minimises the Access window. Not sure if this could be the culprit, or if the user clicking another application can remove the focus.
The back-end of the database is also accessed by up to around 700 users each day.
As it stands, the error trapper pops up with the message, but the front end continues working correctly. It's just an annoying issue to resolve, but am slowly running out of ideas now, and any help would be hugely appreciated!
Error 2475 is thrown when a non-form object is the active screen object such as a table datasheet. I've encountered this error in an application that uses multiple instances of a form and needs to track whether the multiple form module is active or one of the other application module functions in which case all instances of the multiple forms (popups) need to have .visible set to false. I use the Screen.ActiveForm.Name call in the Form_Deactivate event.
You can trap the error in the procedure's error handler and take action knowing the screen's active object is not a form.
Example:
Private Sub Form_Deactivate()
On Error GoTo errHandler
If Screen.ActiveForm.Name <> "AnApplicationForm" Then 'throws 2475 if not a form object
sstatus = "status message"
End If
ExitSub:
Exit Sub
errHandler:
If Err.Number = 2475 Then Resume Next 'screen active object is not a form i.e. datasheet
MsgBox "Error in " & Me.Name & ".Form_Deactivate: " & Err.Number & " - " & Err.Description
Resume ExitSub
End Sub 'Form_Deactivate
I have an alert sending aid built into an Access database that sends emails to all technicians with an expired/ing induction, all in one go. Every email requires permission to send.
Similar to this question and this question but I need to send multiple emails automatically all at once, without holding up other processes.
The code in the questions seems to send a single email, and the only accepted answer involves waiting five seconds up to three times to check that the actual message had been displayed so that SendKeys would work on that window.
If I use SendKeys with a 5 second pause built in to wait for confirmation as Graham Anderson suggests, this won't speed up the process, only avoid some clicking. The progress bar shown on the warning (below) takes roughly that time to fill, so I'm guessing that's the system building the email, which is what the wait is for.
The same problem applies to Julia's answer to the other question - the warning box won't let you click "Allow" until the progress bar is full, so code that auto clicks this button will have to wait to complete at best.
I tried DoCmd.SetWarnings (False) (and then DoCmd.SetWarnings (True) after sending) but that doesn't stop this particular one. This may be because the warning comes from Outlook rather than Access.
The coding I have:
Private Sub SendAlerts_Click()
Dim db As Database, rs As Recordset
Dim Subject As String, Body As String, EmailAddress As String
Dim Recipient As String, Induction As String, Expiry As String
Set db = CurrentDb
Set rs = db.OpenRecordset("qryExpiryAlert", dbOpenDynaset)
Do Until rs.EOF
EmailAddress = rs!Email
Recipient = rs!FullName
Induction = rs!Induction
Expiry = rs!ExpiryDate
Subject = "Inductions need renewal"
Body = "Hi " & Recipient & ", the expiry for your " & Induction & _
" certificate is " & Expiry & ". Please send a current certificate asap."
DoCmd.SendObject , , , EmailAddress, , , Subject, Body, False
rs.MoveNext
Loop
DoCmd.Close
End Sub
Here is the warning:
I wrote and compiled an Autohotkey script that looks for the Outlook confirmation dialog and automatically clicks Allow. (I call this from Access VBA and can set how long it run for before shutting itself off.) As you point out, though, there is still a substantial delay waiting for the Allow button to be enabled each time.
Ultimately, our company ended up purchasing Outlook Security Manager. As usual, you have to add an Outlook Security Manager Reference. reference to your project.
It basically has ON and OFF settings, so it's easy to use. If wrote a Sub in a standard module to simplify:
Public Sub SetSecurityManager(State As String)
' Turns the Security Manager on or off.
' The Security Manager allows the application to
' send emails through Outlook without having to
' manually confirm each outgoing email.
Select Case State
Case "On"
' Temporarily turn off Outlook security so we can send email
Set SecurityManager = CreateObject("AddInExpress.OutlookSecurityManager")
SecurityManager.DisableOOMWarnings = True
SecurityManager.DisableSMAPIWarnings = True
Case "Off"
'Restore Outlook security to normal
SecurityManager.DisableSMAPIWarnings = False
SecurityManager.DisableOOMWarnings = False
Set SecurityManager = Nothing
Case Else
End Select
End Sub
Whenever I need it, I add this line to my code:
SetSecurityManager "On"
It's frustrating to have to pay for a solution to a security problem created by software we purchased, but it's the best answer we've found. I ship between 150 and 225 reports a day and have no problem with OSM.
Thanks,
Keith
I have an Access 2016 application that gets distributed to many users who are not sophisticated users. They usually have to install the MS Runtime for Access. Despite clear directions, too many users still find that the application will not open. It appears that early bound objects are not present on the system. With bound objects not present no code ever loads or runs, so it is not even possible to give a good error message.
I am now attempting to write a small program in which all the objects needed by the application are late bound, thus being able to say which modules are missing, if any. What I am finding though is that my method for detection is failing even when I KNOW the object is present. The code below is an example of one test for a required object. This test always fails and I cannot figure out why. I have about 7 of these. Three seem to work correctly, but the others do not. Is there some different way I should be coding the "CreateObject"?
Private Sub btnOffice_Click()
'Office FileDialog MSO.DLL Microsoft Office 16.0 Object Library
Dim obj As Object
On Error GoTo xyzzy
Set obj = CreateObject("Office.FileDialog")
lblOffice.Caption = "Office module present"
Exit Sub
xyzzy:
lblOffice.Caption = officeWarning
MsgBox Err.Description
End Sub
You're trying to detect broken References. Here's a procedure to check for and report broken references:
Sub CheckReferences()
Dim ref As Reference
For Each ref In References
If ref.IsBroken Then
MsgBox "Broken reference detected: " & vbCrLf & ref.Name & vbCrLf & ref.FullPath, vbOKOnly + vbCritical, "Broken Reference"
End If
Next ref
End Sub
The problem here is that the file dialog is not available as a separate COM object, and thus you can’t use CreateObject() to create such an instance.
However, if you plan to distribute your application without an office reference (and I think you safe to do so – even with runtime), then you can change the FileDialog code to late binding:
Eg this:
Dim f As FileDialog
Set f = Application.FileDialog(msoFileDialogFilePicker)
f.Show
MsgBox "file choose was " & f.SelectedItems(1)
Becomes this:
Dim f As Object
Set f = Application.FileDialog(3)
f.AllowMultiSelect = True
f.Show
MsgBox "file choosen was " & f.SelectedItems(1)
So in your case, the filedialog is not available as a separate COM object, but you can still as above shows adopt late binding anyway. However, in my experience, it IS safe to distribute the runtime with a office reference and thus at least for the office dialog you don't need late binding. For reliability, since in the case of FileDialog the late binding code is not a big deal, then I would continue distribution without the office reference for the FileDialog and use the above late binding.
I'm having difficulty finding any information about this particular issue. The only information I've found is that this seems to have been a bug in Access 2010 (I'm hoping that they fixed it for 2013 and that I'm simply ignorant of the solution).
I'm using the DoCmd.SendObject Method in access vba to send a report via email in outlook upon the on_click event for a command button. My code seems to work just fine and the email goes out as intended. The issue is that after running the code I'm unable to make any changes to the table that serves as the record source to the report, even though the report is closed. I get error 3211 "cannot lock record source because it is in use....."
I've removed the DoCmd.SendObject code and have no issues making changes to the tables and I don't receive the error. I am assuming that the method itself establishes some sort of link or connection between Outlook and the table.
So, my question is how to fix this. Is there VBA code that can terminate the link/connection between outlook and a table after using the DoCmd.SendObject Method?
To all,
I ended up using a different method for sending emails, which ultimately resolved all my issues and turned out to be more flexible than the SendObject method. Below is the code I used, hopefully you will find it useful:
(Just a note for others who find the code useful: I elsewhere used code to create a pdf file, which is why the pdf file name is a variable)
'Create a new e-mail and attach previously created pdf
Dim strLocation As String
Dim OutApp As Object
Dim OutMail As Object
Dim EmailTo As Variant
Set OutApp = CreateObject("Outlook.Application")
Set OutMail = OutApp.CreateItem(0)
EmailTo = DLookup("Email", "tblTempProcessing")
With OutMail
.To = EmailTo
.CC = ""
.BCC = ""
.Subject = "Subject Text"
.Body = "Body Text"
.Attachments.Add ("C:\Folder\SubFolder\" & Variable & ".PDF")
.Send
End With
On Error GoTo 0
I have a report in MS Access 2007 and I would like to send this report as pdf automatically every night without asking a user to run the macro manually or so. I have the following code in a macro:
Dim strRecipient As String
Dim strSubject As String
Dim strMessageBody As String
strRecipient = "emailaddr...#domain.com"
strSubject = "This is the email subject"
strMessageBody = "Here is a whole bunch of interesting text to accompany the attachment."
DoCmd.SendObject acSendReport, "rptNameofReport", acFormatPDF, strRecipient, , , strSubject, strMessageBody, False
In google, it says I can then name this macro as autoexec and use windows task scheduler. However, this does not work in my case becase when I run the code above, I get a security warning message from outlook saying "a program is trying to automatically send email on your behalf
do you want to allow this? if this is unexpected it may be virus and you should choose no"
I don't want this message to appear because I don't want a confirmation from a user since the plan is to send this email automatically at night. Any help will be appreciated!
Thanks in advance,
The only way I've found so far to do this is to make alterations on a user's PC on their version of MS Outlook to allow this bypass since the error is attached and run through outlook, not Access. Here is an article outlining a way to acheive this:
http://www.everythingaccess.com/tutorials.asp?ID=Outlook-Send-E-mail-Without-Security-Warning
A little in depth but does the job. Hopefully this helps! Unfortuantely because of the security model, you cannot just disable it and have to go a little further to allow this type of behavior on a user's machine. The annoying part is setting this up on each user machine if this is going to fire on each machine rather than a central place on the server somewhere.
Look at Outlook Redemption to avoid that Outlook security warning.
Also naming the macro "autoexec" means that Access will attempt to run the macro every time the database is opened. As an alternative, you could give the macro a different name, say "mcrMidniteEmail", then use the /x command-line switch in the task scheduler.
/x mcrMidniteEmail
Edit: If you have a GMail account available, you can also use VBA to send email through that account using SMTP ... without involving Outlook. See Sending Google Mail (Gmail) from MS Access, VBA, Excel, Word...
Following code always worked for me.
Sub CDO_Mail_Small_Text(Mailto, MailCC, Mailtext, Optional Subject = "", Optional Attachment = "")
Dim iMsg As Object
Dim iConf As Object
Dim strbody As String
Dim Flds As Variant
Set iMsg = CreateObject("CDO.Message")
Set iConf = CreateObject("CDO.Configuration")
iConf.Load -1 ' CDO Source Defaults
Set Flds = iConf.Fields
With Flds
.Item("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2
.Item("http://schemas.microsoft.com/cdo/configuration/smtpserver") _
= "mail.Mybusiness.com"
.Item("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = 25
.Update
End With
strbody = "Enter the Email body."
With iMsg
Set .Configuration = iConf
.To = Mailto
.cc = MailCC
.BCC = ""
.From = """Do Not Reply "" <NoReply#MyBusiness.com>"
If Subject = "" Then
.Subject = "EMail Subject"
Else
.Subject = Subject
End If
.TextBody = Mailtext
If Attachment <> "" Then .AddAttachment Attachment
.send
End With
Set iConf = Nothing
Set iMsg = Nothing
End Sub
Of course you could make this code work with gmail or other email servers.
You can always use a Forms 'On Timer' event in conjunction with the 'Timer interval' to call the nightly routine that prepares and sends the email. Just include conditional code to verify that it's time to send the email. Some corporate environments lock down the Windows Task Scheduler, so this is a viable option.