Whats the best way to Programmatically Process New Email Messages and Store Attachments - windows

I have several clients/vendors that distribute reports to me via email. Some of these files are enormous, and need to be removed from email and saved on a file share for processing, as well as to control mailbox size.
Can anyone provide guidance on their recommended method of automatically downloading and saving attachments.
I am in a MS Windows Environment (Client & Server Computers). Emails are on an Microsoft Exchange 2003 Email Server.
Preferred use of Microsoft Technology for consistency across solutions (C#), however I am open to any suggestions, be it C#, VBScript, Perl, Java, Components I should purchase, etc..
Scenario
Each Day bob#whysendmereportsbyemail.com sends an email with the subject "Activity Report for YYYY-MM-DD" to me at
john#myemailaddress.com
Each Email has an attachment named "ActivityReport-YYYY-MM-DD-HH-MI-SS.xls" which I need to save on my filesystem at
"C:\FilesFromBob\ActivityReport-YYYY-MM-DD-HH-MI-SS.xls"
Thanks in advance for any assistance.

Exchange 2003 provides a WebDav API which you can use to access emails, contacts etc.. from a user's account.
There's a few answers about accessing a user's Exchange inbox on SO already. I've previously used this approach for almost exactly the situation you outline, and once you work out the WebDav API model and the structure of the requests and responses, it's not too difficult to extract emails and their attachments.
There are other ways to interact with Exchange 2003 (outlined on SO here), but I've only tried the WebDav approach because it seemed the most reliable.

I finally wrote the code to store messages from Outlook
Unfortunately this code runs from within Outlook, so Outlook has to be open.
I did not yet investigate how to schedule the run, but now its easy to do
Sub SaveOutlookFileAttachments()
Dim oStores As Outlook.Stores
Dim oStore As Outlook.Store
Dim oFolders As Outlook.Folders
Dim oFolder As Outlook.Folder
Dim destFolder As String
Dim oItems As Outlook.Items
Dim oMsg As Outlook.MailItem
Dim oAttachments As Outlook.Attachments
Dim oAttachment As Outlook.Attachment
Dim oExplorer As Outlook.Explorer
destFolder = "\\NetworkShare\OrderDetailReport\"
On Error Resume Next
Set oStores = Application.Session.Stores
For Each oStore In oStores
If oStore.DisplayName = "Inbox" Then
oFolders = oStore.GetSearchFolders
For Each oFolder In oFolders
oItems = oFolder.Items
For Each oMsg In oItems
oAttachments = oMsg.Attachments
For Each oAttachment In oAttachments
If InStr(1, oAttachment.FileName, "orderdetail_", vbTextCompare) Then
'MsgBox ("This File Needs to be Saved: " & oAttachment.FileName)
oAttachment.SaveAsFile (destFolder & oAtch.DisplayName)
End If
Next
Next
Next
End If
Next
End Sub

Related

Outlook OLE Automation: BodyFormat not supported?

I am trying to send an email in Outlook using OLE Automation. At the moment, I am using VBS for testing purposes. When it works, I will switch to another language that supports OLE/COM.
The problem with my code is, that I get error 800a0005 "Invalid procedure call" with argument 'BodyFormat'.
According to the documentation of Microsoft, BodyFormat is existing since Outlook 2003. I am testing with Outlook 2010.
My code:
Set ol = WScript.CreateObject("Outlook.Application")
Set ns = ol.getNamespace("MAPI")
Set newMail = ol.CreateItem(olMailItem)
With newMail
.BodyFormat = olFormatHTML
.HTMLBody = "<HTML><H2>The body of this message will appear in HTML.</H2><BODY>Type the message text here. </BODY></HTML>"
.Display
End With
The background: At the moment, some customers receive emails in TNEF format and can't open the email attachment winmail.dat. So I am trying to force Outlook to use HTML instead of RichText.
What can I do?
Constant olFormatHTML is not defined by default.
Add the following line at the beginning of your VBS code:
Const olFormatHTML = 2

What are the prerequisites for installing CDO.DLL in Windows Server 2012 for VB application

I am upgrading a server from Windows 2003 to 2012 R2.
One of our VB6 applications used CDO.dll for MAPI, i.e. for sending mails.
My question is :
How do I install/register CDO.DLL?
What are the prerequisites for installing CDO.DLL?
Do I need to install Outlook in my server for the application to send mail?
Set objMAPI = New MAPI.Session
objMAPI.Logon ShowDialog:=False, NewSession:=False, ProfileInfo:=gobjINI.gstrExchangeServer & vbLf & gobjINI.gstrProfile
'Add a new mesage to the OUtbo Messages Collection
Set objMSG = objMAPI.Outbox.Messages.Add
'Add the recipient list specified in INI File
'Check if this is a multiple Recipient List (names or groups seperated by semicolons!)
If InStr(1, Recipients, ";") Then
objMSG.Recipients.AddMultiple Recipients, CdoTo
objMSG.Recipients.Resolve
Else
'This section is for handling of single recipient name
'Be aware that this may be an email group list name !
Set objRecipients = objMSG.Recipients.Add(Recipients)
objRecipients.Resolve
End If
'Add Subject Line, Message Content and Send Message
objMSG.Subject = Subject
objMSG.Text = Message
'The Update method adds all our assignments to collecttion
objMSG.Update
'Now let's actually send the message
objMSG.Send
'End MAPI Session
objMAPI.Logoff
Set objMAPI = Nothing
MailSend = True
CDO 1.21 is no longer being developed or supported by Microsoft. You can download the standalone version of MAPI along with CDO 1.21 from https://www.microsoft.com/en-us/download/details.aspx?id=42040. It was last updated in 2014 and no new bug fixes are expected. Functionality wise it has not been updated for the last 15 years.
You can switch to the Outlook Object Model (Namespace object roughly corresponds to the MAPI.Session object).
You can also use Redemption (I am its author) - its RDOSession object is similar to the MAPI.Session object (with a lot more extra features).

VB6 program fails opening Excel 2007 with Automation Error Library not registered

I created this VB6 program on my Windows 7 32bit machine with Office 2010 32bit, which runs fine. Tested it on a Windows 8 64 bit machine with Office 2013 32bit, it works. On one machine with, Windows 7 64 bit and Office 2007(32 bit only) it throws an error during the following piece of code.
The actual error message:
Run-time Error –2147319779 (8002801d) Automation error, Library not
registered
VB6 Code:
If (excel_app Is Nothing) Then
Set excel_app = CreateObject("Excel.Application")
Else
Set excel_app = GetObject(, "Excel.Application")
End If
excel_app.Visible = True
excel_version = excel_app.Application.Version
Set wBook = excel_app.Workbooks.Open(directory_path & "\templates\book1.xlsm")
So it is throwing the error when I open book1. It actual does open it and it has a macro run on Workbook_Open(), this runs right through seemly fine. After it finishes and processing of the program returns to the VB6 program it throws the error.
Here are the project references:
Has anyone come across this and what would be the fix?
[EDIT]
I am obviously doing something wrong here my error handler is throwing an error.
I did try one other thing and that was removed "Set wBook = " and it didn't throw an error. I have placed "Set wBook = " back since then, as I do need it further on in my code.
Dim wBook As Workbook
Dim excel_app As Object
On Error GoTo trialhandler
If (excel_app Is Nothing) Then
Set excel_app = CreateObject("Excel.Application")
Else
Set excel_app = GetObject(, "Excel.Application")
End If
excel_app.Visible = True
excel_version = excel_app.Application.Version
Set wBook = excel_app.Workbooks.Open(directory_path & "\templates\book1.xlsm")
MsgBox ("Exiting")
Exit Sub
trialhandler:
Dim source_string As String
source_string = excel_app.Source 'Error here
MsgBox ("My Error 1:" & source_string)
excel_app.Err
MsgBox ("My Error 2:" & excel_app.Err.Number & " " & excel_app.Err.Description)
Exit Sub
I had Office 2013 installed on this previously, then uninstalled it and placed 2007 on it, could this have any impact? Or the fact that I have created this program with reference to Excel 2010 and now I'm trying to run it against Office 2007? Though it works on the other machine with 2013. Grasping at straws here.
[EDIT 2]
It has passed the initial error to throw exactly the same error later on. This piece imports an mdb table. There must be some early binding left over
With wBook.Worksheets("Seal Register").ListObjects.Add(SourceType:=0, Source:=Array( _
"OLEDB;Provider=Microsoft.ACE.OLEDB.12.0;Password="""";User ID=Admin;Data Source=" & db_full_path & ";" _
, _
"Mode=ReadWrite;Extended Properties="""";Jet OLEDB:System database="""";Jet OLEDB:Registry Path="""";" _
, _
"Jet OLEDB:Database Password="""";Jet OLEDB:Engine Type=5;Jet OLEDB:Database Locking Mode=0;Jet OLEDB:Global Partial Bulk Ops=2;" _
, _
"Jet OLEDB:Global Bulk Transactions=1;Jet OLEDB:New Database Password="""";Jet OLEDB:Create System Database=False;" _
, _
"Jet OLEDB:Encrypt Database=False;Jet OLEDB:Don't Copy Locale on Compact=False;Jet OLEDB:Compact Without Replica Repair=False;" _
, _
"Jet OLEDB:SFP=False;Jet OLEDB:Support Complex Data=False"), _
Destination:=Range("A" & row_number)).QueryTable
.MaintainConnection = False
.CommandType = xlCmdTable
.CommandText = Array(db_table_name)
.RowNumbers = False
.FillAdjacentFormulas = False
.PreserveFormatting = True
.RefreshOnFileOpen = False
.BackgroundQuery = True
.RefreshStyle = 1
.SavePassword = False
.SaveData = True
.AdjustColumnWidth = True
.RefreshPeriod = 0
.PreserveColumnInfo = True
.SourceDataFile = db_full_path
.ListObject.DisplayName = "Table_" & db_table_name
.Refresh BackgroundQuery:=False
End With
There no reason to think this is a vb error.
Returns or sets the name of the object or application that originally generated the error.
object.Source [= stringexpression]
Arguments
object
Always the Err object.
stringexpression
A string expression representing the application that generated the error.
Remarks
The Source property specifies a string expression that is usually the class name or programmatic ID of the object that caused the error. Use Source to provide your users with information when your code is unable to handle an error generated in an accessed object. For example, if you access Microsoft Excel and it generates a Division by zero error, Microsoft Excel sets Err.Number to its error code for that error and sets Source to Excel.Application. Note that if the error is generated in another object called by Microsoft Excel, Excel intercepts the error and sets Err.Number to its own code for Division by zero. However, it leaves the other Err object (including Source) as set by the object that generated the error.
Source always contains the name of the object that originally generated the error — your code can try to handle the error according to the error documentation of the object you accessed. If your error handler fails, you can use the Err object information to describe the error to your user, using Source and the other Err to inform the user which object originally caused the error, its description of the error, and so forth.
From Automating Microsoft Office 97 and Microsoft Office 2000
Lori Turner
Microsoft Corporation
March 2000
PROBLEM:
My Automation client worked fine with the Office 97 version of my application. However, I rebuilt my project and it works fine with Office 2000 but now fails with Office 97. What could be wrong?
New versions of Office include new features and enhance some of the existing ones. To provide clients with programmatic access to these new and enhanced features, the object models must be updated. Because of this update, a method may have more arguments for Office 2000 than it did with Office 97.
The new arguments to existing methods are usually optional. If you use late binding to the Office Automation server, your code should work successfully with either Office 97 or Office 2000. However, if you use early binding, the differences between the 97 and 2000 type libraries could cause you problems in the following situations:
If you create an Automation client in Visual Basic and reference the Office 2000 type library, your code might fail when using an Office 97 server if you call a method or property that has changed.
If you create an MFC Automation client and use the ClassWizard to wrap classes from the Office 2000 type library, your code might fail when using an Office 97 server if you call a method or property that has changed.
To avoid this problem, you should develop your Automation client against the lowest version of the Office server you intend to support. For the best results in maintaining compatibility with multiple versions of Office, you should use late binding. However, if you choose to use early binding, bind to the type library for the earliest version of the Office server you want to support. To illustrate, if you are writing an Automation client with Visual Basic and want that client to work with Excel 97 and Excel 2000, you should reference the Excel 97 type library in your Visual Basic project. Likewise, if you are writing an Automation client using MFC, you should use the ClassWizard to wrap the Excel 97 type library.
For more information, please see the following article in the Microsoft Knowledge Base:
Q224925 INFO: Type Libraries for Office 2000 Have Changed

Is there a way to check the MS Security Center for virus protection status?

We are in a Windows environment and looking to automate this process for non-company machines. If a vendor comes on site, we'd like to be able to have him/her hit a website that can perform a quick scan of the workstation to determine if they have the proper MS KB patches and if their virus scanner dats are up to date.
I can scan for the KB updates relatively easy, what I'm having a hard time finding is a way to check the virus dat status and since there are so many different engines out there, it seemed to make sense to use the (built into XP at least) proprietary MS security center stuff.
Eventually we'd like to have our routers redirect non-company machines to a website that will force validation, but until that point it will be a manual process.
Any thoughts?
In Windows Vista there are some new APIs to interface with the Security Center component status: http://msdn2.microsoft.com/en-us/library/bb963845(VS.85).aspx
Through WMI, here's a VBS code snippet I checked out on http://social.msdn.microsoft.com/forums/en-US/windowssecurity/thread/bd97d9e6-75c1-4f58-9573-9009df5de19b/ to dump Antivirus product information:
Set oWMI = GetObject
("winmgmts:{impersonationLevel=impersonate}!\\.\root\SecurityCenter")
Set colItems = oWMI.ExecQuery("Select * from AntiVirusProduct")
For Each objAntiVirusProduct In colItems
msg = msg & "companyName: " & objAntiVirusProduct.companyName & vbCrLf
msg = msg & "displayName: " & objAntiVirusProduct.displayName & vbCrLf
msg = msg & "instanceGuid: " & objAntiVirusProduct.instanceGuid & vbCrLf
msg = msg & "onAccessScanningEnabled: "
& objAntiVirusProduct.onAccessScanningEnabled & vbCrLf
msg = msg & "productUptoDate: " & objAntiVirusProduct.productUptoDate & vbCrLf
msg = msg & "versionNumber: " & objAntiVirusProduct.versionNumber & vbCrLf
msg = msg & vbCrLf
Next
WScript.Echo msg
For AVs that don’t report to WMI or for AVs which WMI retains state info after the AV is uninstalled (there are instances of both cases) you may wish to consider the OPSWAT library.
You will need to write and deploy a light client from your website to utilize the library to machines to be interrogated.
The library utilizes WMI for security apps that correctly support WMI and proprietary methods to detect AVs and their dat status for those that don’t.

Clear Categories in Outlook 2003

Outlook 2007 automatically strips categories from incoming email.
Outlook 2003 does not do this, forcing the recipient to use the senders categories.
Is there a way to either:
Force Outlook 2003 to remove the categories (can't do it via Rules and Alerts) on incoming email.
OR
Force both Outlook 2007 and Outlook 2003 to remove categories before sending?
Thanks,
Jeff
Try setting up a rule to run a script:
Sub RemoveCategories(MyMail As MailItem)
Dim strID As String
Dim objMail As Outlook.MailItem
strID = MyMail.EntryID
Set objMail = Application.Session.GetItemFromID(strID)
objMail.Categories = ""
objMail.Save
Set objMail = Nothing
End Sub
This is based on this article.

Resources