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
Related
Scenario:
From an Access-form with selected recordset, a report is filled with data, this is converted via VBA into HTML format and sent with Outlook. The content then appears as HTML in the email-body of the recipient. This contains a link that points to the recordset in this form. So assuming the recipient also has ACCESS and also the exact same database (and same location & content), the link would open his database file when clicked, then open the form, then open that exact record by using the query.
Based on this...
...I added a text field into my report with this content and marked it as a hyperlink:
Click here#C:\MainDatabase.accdb#Query frmForm01
Click the hyperlink in the report works (opens Access & file), the link in the locally stored HTML-tempfile also works.
Problem:
Although the link is sent, also appears in the recipient email-body as link "Click here", but displayed link is not clickable, just blue underlined text!
After a lot of experimenting I found out that it's all Outlook! The link is intact in the Outlook-mail-body preview before sending....it must be an Outlook-setting that converts the link into text during/for sending. In the Outlook menu I have already checked the format settings: convert to HTML is OK!(not plain text). So what else could be the cause??
Would be very grateful for solutions. Thanks!
My code:
Sub CreateHTMLMail()
Dim OutApp As Outlook.Application
Dim OutMail As Outlook.MailItem
Dim FSO As Object
Dim AttchFile As String, EmailTo As String, strSig As String
Set OutApp = New Outlook.Application
Set OutMail = OutApp.CreateItem(olMailItem)
AttchFile = "C:\AttachmTemp.htm"
EmailTo = "abcd#efgh.com"
DoCmd.OpenReport "NewReport", acViewReport, , "[ID]='" & Me.ID & "'", acHidden
DoCmd.OutputTo acOutputReport, "NewReport", acFormatHTML, AttchFile
Set FSO = CreateObject("Scripting.FileSystemObject")
strSig = FSO.OpenTextFile(AttchFile).ReadAll
With OutMail
.TO = EmailTo
.Subject = "New Message"
.BodyFormat = olFormatHTML
.HTMLBody = strSig
.send
End With
End If
Kill AttchFile
Set OutApp = Nothing
Set OutMail = Nothing
End Sub
I do this using a custom URL protocol handler.
First, create (and distribute after testing) a .reg file like this (replace myapp by your application name):
Windows Registry Editor Version 5.00
; Andre, 2019
[HKEY_CLASSES_ROOT\myapp]
#="URL:myapp-Open"
"URL Protocol"=""
"EditFlags"=hex:02,00,00,00
[HKEY_CLASSES_ROOT\myapp\DefaultIcon]
#="C:\\path\\myapp\\myapp.ico"
[HKEY_CLASSES_ROOT\myapp\shell]
#="open"
[HKEY_CLASSES_ROOT\myapp\shell\open]
[HKEY_CLASSES_ROOT\myapp\shell\open\command]
; using a .vbs to start my app
; #="wscript C:\\path\\myapp\\Startmyapp.vbs \"%1\""
; (untested) starting Access directly, needs the /cmd switch
#="\"C:\\Program Files (x86)\\Microsoft Office\\Office16\\msaccess.exe\" C:\\path\\myapp\\Myapp.accde /cmd \"%1\""
; If you use Outlook, prevent the Security warning
; https://stackoverflow.com/a/34660198/3820271
; Note: the whole subtree starting with (at least) "Security" will be created.
; This path is for Office 2016.
[HKEY_CURRENT_USER\Software\Policies\Microsoft\Office\16.0\Common\Security\Trusted Protocols\All Applications\myapp:]
Note that I use a .vbs script to start my Access application, it should work as well with the path to msaccess.exe plus your local frontend.
See comments in myapp\shell\open\command
Then in your HTML email, use URLs like this:
url:myapp:ID:2357
ID:2357 will be passed as command-line parameter to your application.
See Opening Microsoft Access with parameters on how to read this string, then parse it in your Autoexec function and open your form.
To test this, simply type myapp:ID:2357 in Start/Run or in a Cmd window.
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.
I have a macro in Access that connects to the running instance of MS Outlook.
The macro had been working, until last week when I started receiving the error: Activex component can't create object whenever I ran the macro.
Here's a piece of the code and where it's currently failing:
Function GatherDailyStats()
Dim oOlAp As Object, oOlns As Object, oOlInb As Object
Dim oOlItm As Object
'Dim FileName As
Dim i, j As Integer
Dim strDir1 As String
Dim strDir2 As String
'~~> Get Outlook instance
Set oOlAp = GetObject(, "Outlook.Application") '--**THIS IS WHERE IT FAILS**
Set oOlns = oOlAp.GetNamespace("MAPI")
Set oOlInb = oOlns.GetDefaultFolder(olFolderInbox).Folders.Item("Daily Stats")
'~~> Check if there are any actual unread emails
If oOlInb.Items.Restrict("[UnRead] = True").Count = 0 Then
MsgBox "NO Unread Email In Daily Stats folder"
Exit Function
End If
Nothing has changed in the code since I created it and tested it thoroughly.
Update: I just tested the same application on a different computer and it worked perfectly there.
Here is a KB article about the ROT and how Office applications by design don't register until their start up sequence has finished. You may be seeing an issue that was always there, just never ran into it before for whatever reason.
Lifted from this discussion you may want to try adding a fall back to make sure that the application is running:
On Error Resume Next
Set objOutlook = GetObject(, "Outlook.Application")
If Err.Number = 429 Then
Set objOutlook = CreateObject("Outlook.Application")
End If
From that same discussion it is important to note that Outlook 2010 apparently has some kind of issue with registering in the ROT when not started in Administrator mode.
Apparently there is a work around that someone has posted which includes:
...if you assign the Everyone group full rights to the Office install
directory it will then work.
Not sure that is the greatest idea but it is a known issue with Office 2010.
EDIT: here is one last resource.
GetObject will throw an error, if the application isn't running. You need to check for this:
On Error Resume Next
Set oOlAp = GetObject(, "Outlook.Application")
If Err.Number <> 0 Then Set oOlAp = New Outlook.Application
Alternatively, you could just create a new instance of your object:
Set oOlAp = CreateObject("Outlook.Application")
Using CreateObject to create a new instance will, of course, increase resource load in cases when an object of same type was already initialized. Saying it differently, to increase performance and lower use of system resources, better use the first suggested solution.
Firstly, always use CreateObject when creating an instance of the Outlook.Application object - Outlook is a singleton, so only one instance will ever be running for the logged in user.
Secondly, what are the versions of Outlook and Access? Are they all the same version>? If not, are they both 32 or 64 bit?
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.
At work we have this reporting tool. It is distributed to everyone as a MDE tool that is locked up pretty good (VBA is unviewable, cannot import any of the table, query, forms, etc). When each person fills out their applicable portion there is a button that conslidates it into a text file, and then sends it to Outlook. Then everyone emails it to one person.
So I have come up with need to use this in my own database:
Remote Employees fill out a form that creates a power point presentation for them, and this part I think I have nailed down. This helps us track metrics on these presentations, rather than the employee manually creating a the ppt, and then we coming behind and manully entering the data from the brief into a form. Makes sense right.
Here is my problem, at the office, this is solved, but for those out in the field I need a similiar tool like the one mentioned above; where they get the benefit of the autogenerated ppt, and then I can have them send me the text file through email I can add to the db.
Here are my questions because I am just getting into the beginning of this:
-The form is pretty long because there is A LOT of info going into a ppt, so I use one form with tabs for different sections, but it all becomes on record in the table, and one ppt. How do I turn all this information, this one record, into a text file, and how do I use the Send to Outlook, all with one button click??
-When the user emails em the text file, how do I import it into the database table?
-How do you lock up a MDE so that the VB is unviewable, and the object cannot be imported into another application?
any other advice, tips, "your crazy man!"s, are welcome! thanks as always!
Have you considered replication rather that a text file? The data would be stored in a replicated back-end file with Access Security, which could be returned to you. CDO should suit for emailing.
Text
Access has DoCmd.TransferText, which will allow you to both export and import a text file.
CDO
Private Sub SendEmailCDO()
'Requires reference to Microsoft CDO for Windows 2000
Dim cdoConfig As Object
Dim strSubject As String
Dim strBody As String
Dim strFile As String
Dim cdoMessage As Object
'Set up detail of the mail server
Set cdoConfig = CreateObject("CDO.Configuration")
With cdoConfig.Fields
.Item(cdoSendUsingMethod) = 2 ''cdoSendUsingPort
.Item(cdoSMTPServerPort) = 25
.Item(cdoSMTPServer) = "smpt.themailserver.com"
.Item(cdoSendUserName) = "abc#themailserver.com"
.Item(cdoSendPassword) = "password"
.Update
End With
''This is the subject line for the email.
strSubject = "Membership List"
''This is the message with a little HTML.
strBody = "<P>Here is the membership list for <FONT color=#ff0000>" _
& Format(Date, "mmmm yyyy") & "</FONT>.</P><P>Regards, LTD</P>"
''Location of Attachment
strFile = "C:\Docs\MembershipList.rtf"
''Set up the email message
Set cdoMessage = CreateObject("CDO.Message")
With cdoMessage
.Configuration = cdoConfig
.Subject = strSubject
.From = "me#here.com"
.To = "someone#there.com"
.HTMLBody = strBody
.AddAttachment strFile
.Send
End With
End Sub
Further information: http://wiki.lessthandot.com/index.php/Access_and_Email
#Justin asks:
-How do you lock up a MDE so that the VB is unviewable, and the object
cannot be imported into another
application?
The question makes no sense, unless the person asking it has failed to grasp what an MDE is. THERE IS NO VIEWABLE CODE LEFT IN AN MDE. It has been stripped out and all that remains is the compiled p-code. For an a helpful article on VBA compilation in Access that incidentally explains the relationship between canonical code and compiled p-code, see Michael Kaplan's "The real deal on the /Decompile switch."
Keep in mind that this applies only to code-bearing objects (forms/reports/modules) and not to tables and queries.