Lori99
asked on
How to read email from Exchange in VB
I have a developer who needs to automatically process an Excel attachment that is emailed daily. He is currently using the Outlook object model to do this. A job runs his VB executable every few minutes to check to see if the email is available. This executable runs on a server that also runs SQL Server and is looking for the email in a profile that is set up on the server.
Frequently, an instance of the OUTLOOK.EXE opened by the VB app does not close properly and continues running until we physically kill it. This is a problem because the running instance of Outlook interferes with SQL Server's ability to send notifications. I do not consider a process to check for Outlook and kill it to be a good solution for this problem.
I did some research on this site and Google and saw several references to using MAPI instead of Outlook to do this type of function. Is this a good solution? If so, code samples on how to access the mail server, read the email and save the attachment would be appreciated. I am only a minimal VB programmer and the developer is not familiar with MAPI. If not, could I get some suggestions on how to prevent the stranded Outlook process?
Frequently, an instance of the OUTLOOK.EXE opened by the VB app does not close properly and continues running until we physically kill it. This is a problem because the running instance of Outlook interferes with SQL Server's ability to send notifications. I do not consider a process to check for Outlook and kill it to be a good solution for this problem.
I did some research on this site and Google and saw several references to using MAPI instead of Outlook to do this type of function. Is this a good solution? If so, code samples on how to access the mail server, read the email and save the attachment would be appreciated. I am only a minimal VB programmer and the developer is not familiar with MAPI. If not, could I get some suggestions on how to prevent the stranded Outlook process?
ASKER
I don't know why Outlook is hanging. This process runs multiple times (like every 5 minutes for several hours) and I suspect it is erroring out at some point and not cleaning up the Outlook session. The developer said he has tried quite a few things, but wasn't able to solve the problem.
This is the portion of the code that has to do with reading the email from Outlook. There is code within this sub that also opens the spreadsheet and writes the contents to a SQL database that I cut out.
sub main()
On Error GoTo FailOut
Dim OutlookApp As Object
Dim myNameSpace As Object
Dim myFolder As Object
Dim myDestFolder As Object
Dim Email As Object
Dim objAttachments As Object
Dim objAttach As Object
Set OutlookApp = CreateObject("Outlook.Appl ication")
Set myNameSpace = OutlookApp.GetNamespace("M API")
Set myFolder = myNameSpace.GetDefaultFold er(olFolde rInbox)
Set myDestFolder = myFolder.Folders("Test")
If myFolder.Items.Count = 0 Then GoTo FailOut
For Each Email In myFolder.Items
If Email.Class = olMail And InStr(1, Email.Subject, "Test") > 0 Then
If Email.Attachments.Count > 0 Then
Set objAttachments = Email.Attachments
For Each objAttach In objAttachments
If Dir("\\server\directory\") = "" Then GoTo FailOut
objAttach.SaveAsFile "\\server\directory\myfile .xls"
Next
Set objAttachments = Nothing
Email.Move myDestFolder
<some code here processes the Excel spreadsheet>
End If
End If
Next Email
OutlookApp.Quit
FailOut:
On Error Resume Next
Set myFolder = Nothing
Set myNameSpace = Nothing
Set OutlookApp = Nothing
Set myDestFolder = Nothing
This is the portion of the code that has to do with reading the email from Outlook. There is code within this sub that also opens the spreadsheet and writes the contents to a SQL database that I cut out.
sub main()
On Error GoTo FailOut
Dim OutlookApp As Object
Dim myNameSpace As Object
Dim myFolder As Object
Dim myDestFolder As Object
Dim Email As Object
Dim objAttachments As Object
Dim objAttach As Object
Set OutlookApp = CreateObject("Outlook.Appl
Set myNameSpace = OutlookApp.GetNamespace("M
Set myFolder = myNameSpace.GetDefaultFold
Set myDestFolder = myFolder.Folders("Test")
If myFolder.Items.Count = 0 Then GoTo FailOut
For Each Email In myFolder.Items
If Email.Class = olMail And InStr(1, Email.Subject, "Test") > 0 Then
If Email.Attachments.Count > 0 Then
Set objAttachments = Email.Attachments
For Each objAttach In objAttachments
If Dir("\\server\directory\")
objAttach.SaveAsFile "\\server\directory\myfile
Next
Set objAttachments = Nothing
Email.Move myDestFolder
<some code here processes the Excel spreadsheet>
End If
End If
Next Email
OutlookApp.Quit
FailOut:
On Error Resume Next
Set myFolder = Nothing
Set myNameSpace = Nothing
Set OutlookApp = Nothing
Set myDestFolder = Nothing
Well, just glancing over the code you supplied very quickly the only thing I see that I'd do differently is to issue an OutlookApp.Logoff command rather than OutlookApp.Quit. I don't think I've ever used Quit to get out of an Outlook application, but I don't know that's more than just personal preference. In other words, I don't know that's what causing the problem. Let me see if I can duplicate the problem and I'll get back to you. Two quick questions. First, is this a true VB application or is it a VBscript routine? Second, are you using Windows built-in scheduler to run this at specific intervals?
I ran some tests using the code you supplied and kept running into problems. Sometimes I'd get an error when the program was trying to terminate the Outlook session, other times when reading through the messages. Rather than spend time right now trying to figure out why, I elected to try the MAPI approach and see if that'd make any difference. It seems to have. Using the code below I ran through about 15 program executions in a row, running at one minute intervals, without a problem. Of course I can't tell if this'll solve the problem you've run into, but it's worth a try. I think the code below pretty well duplicates the functionality of your code. If I missed anything important, then let me know and I'll fix it. The code below was written using VB, not VBScript. If you need VBScript, then I'm sure we can make the necessary mods.
' Include a reference in the project to Microsoft CDO 1.21 Library
Public Sub MAPIVersion()
On Error GoTo MAPIVersionError
Dim objSession As New MAPI.Session, _
objFolder As MAPI.Folder, _
objSubFolder As MAPI.Folder, _
objDestFolder As MAPI.Folder, _
objMessage As MAPI.Message, _
objMovedMessage As MAPI.Message, _
objAttachments As MAPI.Attachments, _
objAttachment As MAPI.Attachment
objSession.Logon "Outlook", "MYPASSWORD", , True
Set objFolder = objSession.GetDefaultFolde r(CdoDefau ltFolderIn box)
Set objDestFolder = objFolder.Folders("Test")
For Each objSubFolder In objFolder.Folders
Debug.Print objSubFolder.Name & " " & objSubFolder.ID
Next
For Each objMessage In objFolder.Messages
Debug.Print objMessage.Subject
If objMessage.Class = CdoMsg And UCase(objMessage.Subject) = "TEST" Then
Set objAttachments = objMessage.Attachments
If objAttachments.Count > 0 Then
For Each objAttachment In objAttachments
objAttachment.WriteToFile App.Path & "\" & objAttachment.Name
Next
Set objAttachment = Nothing
Set objAttachments = Nothing
Set objMovedMessage = objMessage.MoveTo(objDestF older.ID)
End If
End If
Next
objSession.Logoff
GoTo MAPIVersionCleanup
MAPIVersionError:
MsgBox "Houston, we have a problem"
MAPIVersionCleanup:
Set objMessage = Nothing
Set objFolder = Nothing
Set objSession = Nothing
End Sub
' Include a reference in the project to Microsoft CDO 1.21 Library
Public Sub MAPIVersion()
On Error GoTo MAPIVersionError
Dim objSession As New MAPI.Session, _
objFolder As MAPI.Folder, _
objSubFolder As MAPI.Folder, _
objDestFolder As MAPI.Folder, _
objMessage As MAPI.Message, _
objMovedMessage As MAPI.Message, _
objAttachments As MAPI.Attachments, _
objAttachment As MAPI.Attachment
objSession.Logon "Outlook", "MYPASSWORD", , True
Set objFolder = objSession.GetDefaultFolde
Set objDestFolder = objFolder.Folders("Test")
For Each objSubFolder In objFolder.Folders
Debug.Print objSubFolder.Name & " " & objSubFolder.ID
Next
For Each objMessage In objFolder.Messages
Debug.Print objMessage.Subject
If objMessage.Class = CdoMsg And UCase(objMessage.Subject) = "TEST" Then
Set objAttachments = objMessage.Attachments
If objAttachments.Count > 0 Then
For Each objAttachment In objAttachments
objAttachment.WriteToFile App.Path & "\" & objAttachment.Name
Next
Set objAttachment = Nothing
Set objAttachments = Nothing
Set objMovedMessage = objMessage.MoveTo(objDestF
End If
End If
Next
objSession.Logoff
GoTo MAPIVersionCleanup
MAPIVersionError:
MsgBox "Houston, we have a problem"
MAPIVersionCleanup:
Set objMessage = Nothing
Set objFolder = Nothing
Set objSession = Nothing
End Sub
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
BlueDevilFan,
This is great! I really appreciate you going to so much trouble to help. I'm going to pass this code to my developer and have him try it. I'll get back to you on how it works and to award points hopefully sometime today.
This is great! I really appreciate you going to so much trouble to help. I'm going to pass this code to my developer and have him try it. I'll get back to you on how it works and to award points hopefully sometime today.
ASKER
Just as an FYI, this is a true VB 6.0 executable, not VBScript so your code should be fine. It is run from the SQL Server Agent Job Scheduler.
Cool!
ASKER
The code works perfectly! Thanks!
You're welcome. Glad I could help.
BlueDevilfan:
how would i use this code if i wanted to login as an account that is different then what i am already logged into the computer as?
how would i use this code if i wanted to login as an account that is different then what i am already logged into the computer as?
I don't believe that's possible. What version of Outlook are you using?
Hi BlueDevilFan,
Can u help me with this -
I get an error on this line -
Set objDestFolder = objFolder.Folders("Test")
and
objFolder has no value when checked in debug. I changed "Test" to "Misc" (actual folder), but still I get MAPI_E_NOT_FOUND(8004010F) ERROR
AND
Is it possible to login to a specific mail box. For instance, I want to login to a message box on the exchange server, can I do that?
Thank YOu for your help.
CM
Can u help me with this -
I get an error on this line -
Set objDestFolder = objFolder.Folders("Test")
and
objFolder has no value when checked in debug. I changed "Test" to "Misc" (actual folder), but still I get MAPI_E_NOT_FOUND(8004010F)
AND
Is it possible to login to a specific mail box. For instance, I want to login to a message box on the exchange server, can I do that?
Thank YOu for your help.
CM
Hi, CM.
If objFolder has no value (i.e. its value is Nothing), then one of these two lines is failing
objSession.Logon "Outlook", "MYPASSWORD", , False
Set objFolder = objSession.GetDefaultFolde r(CdoDefau ltFolderIn box)
My recommendation is to step through the code in the debugger and see where the failure is occurring. Did you add the reference to the CDO library? If not, then the constant CdoDefaultFolderInbox may not have the correct value.
Yes, you can log into any mailbox on the server so long as you have a profile for that mailbox.
If objFolder has no value (i.e. its value is Nothing), then one of these two lines is failing
objSession.Logon "Outlook", "MYPASSWORD", , False
Set objFolder = objSession.GetDefaultFolde
My recommendation is to step through the code in the debugger and see where the failure is occurring. Did you add the reference to the CDO library? If not, then the constant CdoDefaultFolderInbox may not have the correct value.
Yes, you can log into any mailbox on the server so long as you have a profile for that mailbox.
As to sample code using MAPI, here's a very simple bit of code that reads the messages in the inbox and puts the subjects into a listbox.
'Include a reference to Microsoft CDO 1.21 Library
Dim objSession As New MAPI.Session, _
objFolder As MAPI.Folder, _
objMessage As MAPI.Message
objSession.Logon "Outlook"
Set objFolder = objSession.GetDefaultFolde
For Each objMessage In objFolder.Messages
List1.AddItem objMessage.Subject
Next
objSession.Logoff