Creating table of Outlook Inbox emails in Access - vba

UPDATE:
Current code below in accordance with recommended SQL construct: error in SqlString =
Run-time error '3011': The Microsoft Access database engine could not find the object ". Make sure the object exists and that you spell its name and the path name correctly. If " is not a local object, check your network connection or contact the server administrator.
Of note, I am working on a USAF unclassified network system, and log in via CAC.
Sub InboxImport
Dim SqlString As String
Dim ConnectionString As String
Dim EmailTableName As String
Dim UserIdNum As String
Dim EmailAddr As String
Dim olNS As Outlook.NameSpace
Dim olFol As Outlook.Folder`
Set ol = CreateObject("Outlook.Application")
Set olNS = ol.GetNamespace("MAPI")
Set olFol = olNS.GetDefaultFolder(olFolderInbox)
EmailTableName = "MyInbox" 'My table name
UserIdNum = Environ("USERNAME") '1277523A... acct #
EmailAddr = olFol.Parent.name 'user's email address
ConnectionString = "Outlook 9.0;MAPILEVEL=" & EmailAddr & "|;PROFILE=Default Outlook Profile;TABLETYPE=0;TABLENAME=MyInbox;COLSETVERSION=12.0;DATABASE=C:\Users\" & UserIdNum & "\AppData\Local\Temp\"
SqlString = "SELECT [From] As [Sender], [Sender Name] As SenderName, [Subject Prefix] & [Normalized Subject] As Subject, [Contents] As [Body], [Received] As [ReceivedTime]" & _
" INTO [Email]" & _
" From [" & ConnectionString & "].[MyInbox]"
DoCmd.RunSQL SqlString
end sub
Original text:
I am attempting to pull default Outlook inbox emails into a table within Access. I am able to use the wizard to successfully retrieve emails and populate the various columns and view my current inbox via Access table named "Inbox".
My Access database will be used by several employees at the same time, and I can't ask them to run the wizard for every different computer they log into.
I am using code copied from middle of the page..."Export Outlook Emails to Access table - VBA".
I'm attempting to use
DoCmd.RunSQL "INSERT INTO [Email] " & _
"([Sender], [SenderName], [Subject], [Body], [ReceivedTime])" & _
"VALUES " & _
"'" & objProp(i).Sender & "', '" & _ 'ERROR!
objProp(i).SenderName & "', " & _ 'ERROR!
objProp(i).Subject & "', '" & _
objProp(i).Body & "', '" & _ 'ERROR!
objProp(i).ReceivedTime & "';"
The code stumbles looking at any MailItem property other than .ReceivedTime or .Subject, and those properties throw an error of...
Run-time error '287': Application-defined or object-defined error
For my References - Database:
Visual Basic For Applications
Microsoft Access 15.0 Object Library
OLE Automation
Microsoft Office 15.0 Access database engine Object Library
Microsoft Internet Controls
Microsoft Outlook 15.0 Object Library

I strongly recommend you don't take the tried approach when importing mail from Outlook. Access can natively work with Outlook Data Files in SQL queries. You can, of course, execute these queries using VBA. But it will be way more optimized.
The trick is getting the proper connection string. You can easily obtain the connection string by using the following process:
Create a linked table to the desired outlook folder under External Data -> More -> Outlook folder, choose linked table, select the folder
Use Debug.Print CurrentDb.TableDefs!MyLinkedOutlookFolder.Connect to obtain the connection string, and Debug.Print CurrentDb.TableDefs!MyLinkedOutlookFolder.SourceTableName to obtain the external table name
Execute the following query, using your obtained variables:
SELECT [From] As [Sender], [Sender Name] As SenderName, [Subject Prefix] & [Normalized Subject] As Subject, [Contents] As [Body], [Received] As [ReceivedTime]
INTO [Email]
FROM [ThatConnectionString].[ThatSourceTableName]
Sample connection string:
Outlook 9.0;MAPILEVEL=me#example.com|;PROFILE=Default Outlook Profile;TABLETYPE=0;TABLENAME=Inbox;COLSETVERSION=12.0;DATABASE=C:\Users\Me\AppData\Local\Temp\
Sample source table name:
Inbox
That's all you need, no complex VBA needed.

Related

Can't insert records from Excel to SharePoint

Currently I am suffering Excel ADO issue.
Here is the thing taht
I was trying to insert some records
from "Excel table" to "SharePoint list" Using ADO connection.
But failed (Can't recognize Excel table in SQL Statement)
Dim SQL As String
Dim CN As New ADODB.Connection
Dim OLEDB As String
Dim LIST As String
Dim SITE As String
LIST = "{EE028282-3D7E-4D37-93EE-50FB69C4432C}"
SITE = "https://asml.sharepoint.com/teams/FFKR_DUV_YS_Installation_and_Relocation/Product"
OLEDB = "Provider=Microsoft.ACE.OLEDB.12.0;WSS;IMEX=0;RetrieveIds=Yes;" & _
"DATABASE=" & SITE & ";" & _
"LIST=" & LIST & ";"
Set CN = New ADODB.Connection
CN.Open OLEDB
SQL = SQL & "INSERT INTO Schedule_DB (NAME,TYPE_W) "
SQL = SQL & "SELECT * "
SQL = SQL & "FROM [" & ThisWorkbook.FullName & "].[S_RAW$] "
CN.Execute CommandText:=SQL
CN.Close
If I run it I got error ->
Error image
I have already check the miss-spell, and the amount of item is too much, so I would prefer to process it as a one SQL statement.
"Excel to Excel" works well But still have no ideas for "Excel to SharePoint List".
Please share your advice.
When you want to read data from your Excel sheet you need to have a ADODB.Connection with Read permission, then to write data to your SharePoint List you need to have another ADODB.Connection with Write permission.
Note: You can't transport your whole data in that way, You can generate a big command with whole data then use it or generate command for each record of your Excel data.
About your exception it is simply says it can't find your sheet name in SharePoint Lists.
A sample to guide you can be something like this:
Dim cnnXl As New ADODB.Connection
Dim rsXl As New ADODB.Recordset
Dim cnnShP As New ADODB.Connection
conStrXl = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source='C:\yourExcel.xlsx';" & _
"Extended Properties=""Excel 12.0;HDR=YES;IMEX=1;"";"
commandXl = "SELECT [Field1], [Field2] FROM [Worksheet$$A1:D7] WHERE [Thing1] > 1"
conStrShP = "Provider=Microsoft.ACE.OLEDB.12.0;WSS;IMEX=0;RetrieveIds=Yes;" & _
"DATABASE=yourSite;LIST={yourListCLSID};"
Then open cnnXl and run commandXl and read data to rsXl.
Then open cnnShP and loop over rsXl records and create your commandShP and execute it.

Export from Excel to SQL: Login Failed for User

I'm trying to create a function within Excel that will write data to my remote SQL Server database with a click of a button. However, I keep getting an error telling me that that my login failed for user "UserName" (Error 80040e4d).
At first I thought there must be a problem with my User/Login within the database, so I went to the remote desktop, opened SQL Server Management Studio and checked all my permissions, made sure Windows authentication was selected, checked the password etc... Still didn't work.
My User has been given Read and Write permissions, so I tried to import data into Excel from SQL, which did work. So I'm assuming this must be an issue within my VBA code, more specifically, my connection string.
I would appreciate it if someone could take a look over it, and tell me what I'm doing wrong? Or if someone else has had this issue and knows what's causing it?
Here's the code I have:
Sub Button3_Click()
Dim conn As New ADODB.Connection
Dim iRowNo As Integer
Dim sArtistId, sForename, sSurname, sNationality, sBirthDate, sDeathDate As String
With Sheets("NewArtist")
'Open a connection to SQL Server
conn.Open "Provider=SQLOLEDB;Data Source=tcp:IPADDRESS,1433\SqlServer2008;" & _
"Initial Catalog=DatabaseName;User ID=UserName;Password=PassWord" & _
"Integrated Security=SSPI;"
'Skip the header row
iRowNo = 2
'Loop until empty cell in CustomerId
Do Until .Cells(iRowNo, 1) = ""
sCustomerId = .Cells(iRowNo, 1)
sFirstName = .Cells(iRowNo, 2)
sLastName = .Cells(iRowNo, 3)
'Generate and execute sql statement to import the excel rows to SQL Server table
conn.Execute "insert into dbo.Components (ArtistId, Forename, Surname, Nationality, BirthDate, DeathDate) values ('" & sArtistId & "', '" & sForename & "', '" & sSurname & "', '" & sNationality & "', '" & sBirthDate & "', '" & DeathDate & "')"
iRowNo = iRowNo + 1
Loop
MsgBox "Artists imported."
conn.Close
Set conn = Nothing
End With
End Sub
Thank you very much!
TW
Integrated Security=SSPI
this parameter in your connection string means you are going to pass your windows principal name as authentication, so the sql login and password are being ignored.
you should remove this name/value pair from the connection string, if you want to use a specified username and password.

Command$() worked in Access 2007 but does not work in Access 2013

Items using:
Access 2013 Database Source is the .accdb (referenced as "Source")
Access 2013 Database .accde of the source. (referenced as "CurrentVersion")
The user has a copy of the CurrentVersion on their C:\AccessSystems folder (referenced as "UserVersion")
SQL Database table linked to "Source" named VersionControl2013.
Table contains: System_Name, Version_Number, MDE_Path_Name and MDE_Name.
The flow:
Developer makes a change in Source
Developer updates the Category to the next version number. Category is in the Databases properties.
Developer creates CurrentVersion and saves it to P:\ drive (where all the CurrentVersions are saved).
User opens UserVersion and code runs to check to see if it matches CurrentVersion.
User opts to update and code runs to close UserVersion and copy CurrentVersion to User's c:\AccessSystems folder.
Now... User is up to date with correct version.
UserVersion is opened by the user, on opening it checks to see if the version matches using below code:
Public Sub CheckVersionNumber()
Dim SQLConn As New ADODB.Connection
Dim AnswerSet As New ADODB.Recordset
Set dbs = CurrentDb
Set cnt = dbs.Containers!Databases
Set doc = cnt.documents!SummaryInfo
doc.Properties.Refresh
Set ThisVersion = doc.Properties("Category")
Set SystemName = doc.Properties("Title")
Set SQLConn = New ADODB.Connection
SQLConn.Provider = "sqloledb"
SQLConn.Open "Data Source=scgcserver1;Initial Catalog=SCGCDatawarehouse "
QueryString = "SELECT VersionControl2013.* FROM VersionControl2013 WHERE (((VersionControl2013.System_Name)=" & "'" & SystemName & "'" & "));"
AnswerSet.Open QueryString, SQLConn, , adCmdText
If AnswerSet.EOF = False Then
If RTrim(AnswerSet("Version_Number")) = ThisVersion Then
Else
MsgBox ("Version Number does not match")
ServDir = "p:\accesssytems"
Shell "MsAccess.exe " & "P:\AccessSystems\VersionControl\VersionControl2013.accde"
Application.Quit
End If
End If
AnswerSet.Close
With SQLConn
.Close
End With
End Sub
Note: The code below works in Access 2007. It will not work in Access 2013.
When CurrentVersion is called and opened it runs the code below:
Public Function LoadVersion()
DialogMessage = "You have a previous version of the Application, Do you want to UPDATE your version?"
DialogStyle = vbYesNo + vbDefaultButton1
DialogTitle = "Update Application"
DialogResponse = MsgBox(DialogMessage, DialogStyle, DialogTitle)
If DialogResponse = vbYes Then
ApplicationName = Command$()
Call GetApplicationInformation
DoCmd.Hourglass True
ToDirectory = "C:\AccessSystems\" & RTrim(DatabaseName)
FromDirectory = RTrim(MDEPathName) & RTrim(DatabaseName)
FileCopy "p:\AccessSystems\compiles\Access2013Compiles\" & DatabaseName, "c:\AccessSystems\" & DatabaseName
MsgBox ("Your Client Copy has been updated - Thank You " & " " & ApplicationName & " " & DatabaseName)
Shell "MsAccess.exe " & "C:\AccessSystems\" & RTrim(DatabaseName)
Application.Quit
End If
End Function
Public Sub GetApplicationInformation()
Dim SQLConn As New ADODB.Connection
Dim AnswerSet As New ADODB.Recordset
Set SQLConn = New ADODB.Connection
SQLConn.Provider = "sqloledb"
SQLConn.Open "Data Source=scgcserver1;Initial Catalog=SCGCDatawarehouse "
QueryString = "SELECT VersionControl2013.* FROM VersionControl2013 WHERE (((VersionControl2013.System_Name)=" & "'" & ApplicationName & "'" & "));"
AnswerSet.Open QueryString, SQLConn, , adCmdText
If AnswerSet.EOF = False Then
DatabaseName = AnswerSet("MDE_Name")
MDEPathName = AnswerSet("MDE_Path_Name")
End If
AnswerSet.Close
With SQLConn
.Close
End With
End Sub
I get a runtime error
52: Bad file name or number.
Debug takes it to line and DatabaseName is "".
FileCopy "p:\AccessSystems\compiles\Access2013Compiles\" & DatabaseName, "c:\AccessSystems\" & DatabaseName
I feel the line: ApplicationName = Command$() has something to do with it because ApplicationName is blank also. It is supposed to bring in the application's name.
Why does it work in 2007, but not in 2013?
That's a rather convoluted system you have there.
The Command() function returns a string that was appended to the Access command line with the /cmd switch.
You'd have to launch Access e.g. like this
"MSACCESS.EXE C:\mypath\Database1.accdb /cmd SomeString"
then if Database1.accdb calls Command(), it returns "SomeString".
But if I understand you correctly, the upper code launches the lower code with
Shell "MsAccess.exe " & "P:\AccessSystems\VersionControl\VersionControl2013.accde"
There is no /cmd switch, so Command() won't return anything.
Did it perhaps get lost in the switch to Access 2013?
EDIT:
As I wrote above, ApplicationName = Command$() cannot work in the lower code, because no /cmd string is passed here:
Shell "MsAccess.exe " & "P:\AccessSystems\VersionControl\VersionControl2013.accde"
It is used here:
WHERE VersionControl2013.System_Name = " & "'" & ApplicationName & "'"
so you need to pass whatever is the correct VersionControl2013.System_Name, like this:
Shell "MsAccess.exe " & "P:\AccessSystems\VersionControl\VersionControl2013.accde /cmd mySystemName"
Or if System_Name is simply the database (UserVersion) name, something like this:
Shell "MsAccess.exe " & "P:\AccessSystems\VersionControl\VersionControl2013.accde /cmd " & Dir(CurrentDb.Name)
I used Dir() to extract the file name from the full path.
Perhaps I am not seeing all the code or missing something but... normally you need to declare DatabaseName as a public variable available to all subroutines.
Or .. pass the values back to the calling statement.
Call like this:
databasename = GetApplicationInformation()
The function would look like this:
Public Function GetApplicationInformation() As String
...
GetApplicationInformation = AnswerSet("MDE_Name") ' the database name
But of course this does not explain why it worked in Access 2007. perhaps some more detail from you would help.

How to limit the number of results in an LDAP query

I'm programming an Office 2010 Word template that needs to interact with the Active Directory, to retrieve some user info. The user filling out the template can give some input for the search that is used to retrieve the AD info.
I'm using the ADODB Recordset and Command to setup my query:
Public Function GetActiveDirectoryInfo(searchString As String) As Object
Dim adoCommand, adoConnection, strBase, strFilter, strAttributes
Dim strQuery, adoRecordset
'remove user input asteriks
searchString = Replace(searchString, "*", "")
' Setup ADO objects.
Set adoCommand = CreateObject("ADODB.Command")
Set adoConnection = CreateObject("ADODB.Connection")
adoConnection.Provider = "ADsDSOObject"
adoConnection.Open "Active Directory Provider"
Set adoCommand.ActiveConnection = adoConnection
strBase = "<LDAP://" & GLOBAL_LDAP_USER_OU & ">"
' Filter on user objects.
strFilter = "(&(objectCategory=person)(objectClass=user)(|(sn=" & searchString & "*)(cn=" & searchString & "*)))"
' Comma delimited list of attribute values to retrieve.
strAttributes = ACTIVE_DIRECTORY_FIELDS
' Construct the LDAP syntax query.
strQuery = strBase & ";" & strFilter & ";" & strAttributes & ";OneLevel"
adoCommand.CommandText = strQuery
adoCommand.Properties("Page Size") = 10
adoCommand.Properties("Timeout") = 30
adoCommand.Properties("Cache Results") = False
'adoCommand.Properties("Maximum Rows") = 10 'error: read only
On Error GoTo err_NoConnection
' Run the query.
Set adoRecordset = adoCommand.Execute
Set foundItems = adoRecordset
Debug.Print "Found : " & foundItems.RecordCount & " records"
Exit Function
err_NoConnection:
'in case of error: return <nothing>
Debug.Print Err.description
Set GetActiveDirectoryInfo = Nothing
End Function
THis function is part of a User Class in MS Word.
My question: how to prevent the user from retrieving thousands of records? I have been reading about paging, but that seems more like a network-load-thing than actually limiting the search results that will eventually get back to me.
I've tried several things but with no results. For instance setting the MaxRecords or Maximum Rows properties. Both give an error (non existing property for the first, and read only error for the second).
ANy ideas anyone.
MS Office 2010 dutch
ADO Objects 6.0
Thanx!
Unfortunately ADO MaxRecord that limits the number of search results is not implemented for ADsDSObject. The link https://support.microsoft.com/kb/269361 details the workaround to solve the issue.

How to locate a rogue SELECT statement in an Access frontend?

I have two version of my access frontend. One for Access 2003 which is still being run by a few computers not yet upgraded to Access2010 and Win7, the Acces2010 version unfortunately is caused in Access crash in 2003 at close of the mainform that I have been unable to fix. Backend is SqlServer 2005 SqlExpress version.
Therefore I am stuck with the older frontend for 2003 people, who fortunately don't need the newer capabilities in 2010 version.
Now, a maintenance utility which loads data from a mainframe dump is getting blocked by a "SELECT 1 on Patient_Clinic_Visits" when the Access 2003 version is running somewhere. What I can't find, is where that "SELECT 1 on Patient_Clinic_visits" is coming from.
I have looked in all the module code, and all the queries, but can't find anything like that.
I assume it must therefore be in the frontend form, but how do iI search that without looking through all the objects and controls of that form for RecordSource with some SQL code in it?
cheers,
JonHD
In the end I searched some other questions and thought about programmatically dumping the likely offending information. This is my concoction of two different answers to do what I want. Do to the limits of the Instant Window in VBA over how many lines it will keep from a Debug.Print, I have used WScript object to dump to a log file.
The code basically:
opens each form in the database in turn
dumps its RecordSource description
then for each control on its form, dumps relevant information that MAY contain SQL in some way
note: I use the fact that a Writeline (some code) that causes and error will fail and not write to avoid a lot of testing for different control types for which properties to dump or not dump.
then closed the forms
then it goes through all the queries in the database, and dumps SQL code
(Note1: in the end this didn't find the answer to my problem - see my other recent question!!)
(Note2: this was a quick and dirty script. I noticed the first time it ran the WriteStream didn't write anything, even though it on Step ing through the code it seemed to be doing something. Anyhow when I ran it again it worked. Haven't taken the time to debug why!).
Function DumpFormsAndQueries()
Dim obj As AccessObject
Dim objctrl As Control
Dim frm As Form
Dim dbs As Object
Dim fsoSysObj As FileSystemObject
Dim filFile As Object
Dim txsStream As TextStream
Dim strPath As String
Set dbs = Application.CurrentProject
Set fsoSysObj = New FileSystemObject
' Return Windows Temp folder.
strPath = "C:\Temp\"
On Error Resume Next
' See if file already exists.
Set filFile = fsoSysObj.GetFile(strPath & "Database_Form_dump.Log")
' If not, then create it.
If Err <> 0 Then
Set filFile = fsoSysObj.CreateTextFile(strPath & "Database_Form_dump.Log")
End If
Debug.Print ">> dumping to: " & strPath & "Database_form_dump.log"
Set txsStream = filFile.OpenAsTextStream(ForAppending)
For Each obj In dbs.AllForms
DoCmd.OpenForm obj.name, acDesign
Set frm = Forms(obj.name)
Debug.Print ">>>> dump form: " & obj.name
txsStream.WriteLine "====================================================================="
txsStream.WriteLine "Form : " & obj.name
txsStream.WriteLine "RecordSource: " & frm.RecordSource
txsStream.WriteLine "====================================================================="
For Each objctrl In frm.Controls
txsStream.WriteLine " --------------------------------------------------"
txsStream.WriteLine " : " & objctrl.name & " Type = " & TypeName(objctrl)
txsStream.WriteLine " --------------------------------------------------"
On Error Resume Next
txsStream.WriteLine " >>>> Recordsource: (" & objctrl.RecordSource & ")"
txsStream.WriteLine " >>>> Controlsource: (" & objctrl.ControlSource & ")"
txsStream.WriteLine " >>>> Rowsource: (" & objctrl.RowSource & ")"
txsStream.WriteLine " >>>> Caption: (" & objctrl.Caption & ")"
txsStream.WriteLine " >>>> Text: (" & objctrl.Text & ")"
txsStream.WriteBlankLines 1
Next objctrl
DoCmd.Close acForm, obj.name, acSaveNo
txsStream.WriteBlankLines 3
Next obj
txsStream.WriteLine "====================================================================="
txsStream.WriteLine " Q U E R I E S - in database"
txsStream.WriteLine "====================================================================="
Dim db As DAO.Database
Dim qdf As DAO.QueryDef
Set db = CurrentDb()
For Each qdf In db.QueryDefs
txsStream.WriteLine "Query: " & qdf.name
txsStream.WriteLine "SQL (start) ---------------------------------------------------- "
txsStream.WriteLine qdf.sql
txsStream.WriteLine "SQL (end) ---------------------------------------------------- "
Next qdf
Set qdf = Nothing
Set db = Nothing
txsStream.Close
Debug.Print ">> ended"
End Function
In Access menu select Database Tools->Database Documenter. There, select all objects and push OK. It will take some time, but then you will be presented with a report that lists everything in your database, including the code at the end.
The report could be quite big for big databases.
You can export the report to Word (there is an option for it). There, search for your string. (I think it should be "SELECT 1 from Patient_Clinic_visits")