Solved

Outlook automation in C#

Posted on 2004-04-13
36
1,735 Views
Last Modified: 2008-12-19
I need a jumpstart getting Outlook automation working under C#:

Here are the requirements:

1)  I need to be able to navigate to a specific folder in Outlook
2)  Once I am in this folder, I need to programmatically loop through the e-mails in the folder.
3)  Inside the loop, I need to open each e-mail and read the message body into a C# string variable.
4)  Then I want to parse the string variable (containing the e-mail message body) and look for certain phrases.

#4 I can do, but 1 thru 3 I'd like some sample code.

Please only respond if you are pretty experienced in Outlook Automation and can provide working code in C# only.

My Sincere Thanks,


Tom
0
Comment
Question by:knowlton
  • 21
  • 15
36 Comments
 
LVL 8

Expert Comment

by:RomanPetrenko
ID: 10816930
Take a look here:

.NET Connector for Microsoft Outlook
http://www.codeproject.com/csharp/OutlookConnector.asp

Here you can find good list of How-To's about programming outlook in VS.NET
http://www.microeye.com/resources/res_tech_vsnet.htm

Later I'll give you sample for Outlook 2003(Only this version I have), But I think you can get  some information from links I posted above...
0
 
LVL 5

Author Comment

by:knowlton
ID: 10816960
I've been to both sites and they are not *quite* what I am looking for.

For example, they always seem to navigate to default folders that Outlook provides, using constants.

I need to know how to navigate to a folder that Outlook does not provide.....one that I created myself.
0
 
LVL 5

Author Comment

by:knowlton
ID: 10817140
Roman:

I look forward to seeing your sample code.

Here is what I have so far, plus pseudocode describing what I want to accomplish:

private void ProcessFailures()
            {

                  Outlook.Application oApp;
                  Outlook._NameSpace oNameSpace;
                  Outlook.MAPIFolder oFolder;

                  oApp = new Outlook.ApplicationClass();
                  oNameSpace = oApp.GetNamespace("MAPI");
                  oNameSpace.Logon(null,null,true,true);

                  oFolder.MoveTo("FaxSuccess");  //navigate to custom folder??????

//loop through folder contents
//assign message body to a C# string variable
//parse string variable looking for certain tokens






                  //objOutlook.Explorers objOutlookExplorer = objOutlook.Explorers.Add(objOutlook.ActiveExplorer
                  
            }
0
U.S. Department of Agriculture and Acronis Access

With the new era of mobile computing, smartphones and tablets, wireless communications and cloud services, the USDA sought to take advantage of a mobilized workforce and the blurring lines between personal and corporate computing resources.

 
LVL 5

Author Comment

by:knowlton
ID: 10817513
Inside OnStart just before call to ProcessFailures
Inside ProcessFailures beginning of Try
Exception thrown inside function ProcessFailures.  Message:  Could not complete the operation because the service provider does not support it.::StackTrace:     at Outlook.NameSpaceClass.get_Folders()
   at WindowsServiceTrackRequestProgress.ServiceTrackRequestProgress.ProcessFailures() in n:\clientdevelopment\neo\buyersfund\windowsservicetrackrequestprogress\servicetrackrequestprogress.cs:line 101
etrackrequestprogress\servicetrackrequestprogress.cs:line 99

How can it not be supported?
0
 
LVL 8

Expert Comment

by:RomanPetrenko
ID: 10822840
Here is the sample:

private Outlook.MAPIFolder GotoFolder(Outlook.MAPIFolder fldr, string FolderName)
{
if (fldr == null ) return null;
if (fldr.Name == FolderName) return fldr;
foreach( Outlook.MAPIFolder folder in fldr.Folders)
{
      if (folder.DefaultItemType != Outlook.OlItemType.olMailItem)
            continue;
      if (folder.Name == FolderName)
            return folder;
      Outlook.MAPIFolder f = GotoFolder(folder,FolderName);
      if (f != null)
            return f;
}
return null;
}

private void button1_Click(object sender, System.EventArgs e)
{
string FolderName = "Anekdots";//<=== Folder name you want to open.
oApp = new Outlook.ApplicationClass();
oNamespace = oApp.GetNamespace("MAPI");
oNamespace.Logon(null,null,true,true);
Outlook.MAPIFolder fldr = GotoFolder(oNamespace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox) ,FolderName);<-- if you have more than one account,get corresponding folder from oNamespace.Folders collection
if (fldr == null)
      MessageBox.Show("Folder Not Found");
if (fldr.DefaultItemType != Outlook.OlItemType.olMailItem )
      MessageBox.Show("Can't work with non-Mail Items");
foreach(Outlook.MailItem mitem in fldr.Items)
{
      string forParsing = mitem.Body; <<=== Here if you running this code from external application you'll get outlook warning "Another program tying to access ... bla-bla-bla... Allow access for 1(2)(5) minute(s)?". You will not recieve this message if you are running in Outlook addin or outlook custom form code.
      //<write here parsing code>
}
}
0
 
LVL 5

Author Comment

by:knowlton
ID: 10824621
Roman:

Getting a bunch of errors with your sample code.  Can you please help me debug?

http://www.knowltonfamily.com/a.gif


Here are the errors:

N:\ClientDevelopment\NEO\BuyersFund\WindowsServiceTrackRequestProgress\ServiceTrackRequestProgress.cs(126): foreach statement cannot operate on variables of type 'Outlook.Items' because 'Outlook.Items' does not contain a definition for 'GetEnumerator', or it is inaccessible
N:\ClientDevelopment\NEO\BuyersFund\WindowsServiceTrackRequestProgress\ServiceTrackRequestProgress.cs(93): foreach statement cannot operate on variables of type 'Outlook.Folders' because 'Outlook.Folders' does not contain a definition for 'GetEnumerator', or it is inaccessible
N:\ClientDevelopment\NEO\BuyersFund\WindowsServiceTrackRequestProgress\ServiceTrackRequestProgress.cs(110): The name 'oApp' does not exist in the class or namespace 'WindowsServiceTrackRequestProgress.ServiceTrackRequestProgress'
N:\ClientDevelopment\NEO\BuyersFund\WindowsServiceTrackRequestProgress\ServiceTrackRequestProgress.cs(111): The name 'oNamespace' does not exist in the class or namespace 'WindowsServiceTrackRequestProgress.ServiceTrackRequestProgress'
N:\ClientDevelopment\NEO\BuyersFund\WindowsServiceTrackRequestProgress\ServiceTrackRequestProgress.cs(112): The type or namespace name 'oNamespace' could not be found (are you missing a using directive or an assembly reference?)
N:\ClientDevelopment\NEO\BuyersFund\WindowsServiceTrackRequestProgress\ServiceTrackRequestProgress.cs(114): The type or namespace name 'oNamespace' could not be found (are you missing a using directive or an assembly reference?)
N:\ClientDevelopment\NEO\BuyersFund\WindowsServiceTrackRequestProgress\ServiceTrackRequestProgress.cs(117): The type or namespace name 'MessageBox' could not be found (are you missing a using directive or an assembly reference?)
N:\ClientDevelopment\NEO\BuyersFund\WindowsServiceTrackRequestProgress\ServiceTrackRequestProgress.cs(122): The type or namespace name 'MessageBox' could not be found (are you missing a using directive or an assembly reference?)
0
 
LVL 5

Author Comment

by:knowlton
ID: 10824637
Sorry, the screenshot is:

http://www.knowltonfamily.com/b.gif
0
 
LVL 5

Author Comment

by:knowlton
ID: 10824782
UPDATE:

Roman, I have taken the errors down to just 2 errors:


http://www.knowltonfamily.com/c.gif


Some problem with the foreach statement:

N:\ClientDevelopment\NEO\BuyersFund\WindowsServiceTrackRequestProgress\ServiceTrackRequestProgress.cs(93): foreach statement cannot operate on variables of type 'Outlook.Folders' because 'Outlook.Folders' does not contain a definition for 'GetEnumerator', or it is inaccessible
N:\ClientDevelopment\NEO\BuyersFund\WindowsServiceTrackRequestProgress\ServiceTrackRequestProgress.cs(130): foreach statement cannot operate on variables of type 'Outlook.Items' because 'Outlook.Items' does not contain a definition for 'GetEnumerator', or it is inaccessible




Here is my updated source code for the Windows Service:


using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.ServiceProcess;

namespace WindowsServiceTrackRequestProgress
{
      public class ServiceTrackRequestProgress : System.ServiceProcess.ServiceBase
      {
            /// <summary>
            /// Required designer variable.
            /// </summary>
            private System.ComponentModel.Container components = null;
            private System.Timers.Timer timerCheckFaxStatus;

            public BuyersFund.GatherMessages.GatherMessages gmMessage = new BuyersFund.GatherMessages.GatherMessages();

            public ServiceTrackRequestProgress()
            {
                  // This call is required by the Windows.Forms Component Designer.
                  InitializeComponent();

                  // TODO: Add any initialization after the InitComponent call
            }

            // The main entry point for the process
            static void Main()
            {
                  System.ServiceProcess.ServiceBase[] ServicesToRun;
      
                  // More than one user Service may run within the same process. To add
                  // another service to this process, change the following line to
                  // create a second service object. For example,
                  //
                  //   ServicesToRun = New System.ServiceProcess.ServiceBase[] {new Service1(), new MySecondUserService()};
                  //
                  ServicesToRun = new System.ServiceProcess.ServiceBase[] { new ServiceTrackRequestProgress() };

                  System.ServiceProcess.ServiceBase.Run(ServicesToRun);
            }

            /// <summary>
            /// Required method for Designer support - do not modify
            /// the contents of this method with the code editor.
            /// </summary>
            private void InitializeComponent()
            {
                  this.timerCheckFaxStatus = new System.Timers.Timer();
                  ((System.ComponentModel.ISupportInitialize)(this.timerCheckFaxStatus)).BeginInit();
                  //
                  // timerCheckFaxStatus
                  //
                  this.timerCheckFaxStatus.Interval = 5000;
                  this.timerCheckFaxStatus.Elapsed += new System.Timers.ElapsedEventHandler(this.timerCheckFaxStatus_Elapsed);
                  //
                  // ServiceTrackRequestProgress
                  //
                  this.ServiceName = "Service1";
                  ((System.ComponentModel.ISupportInitialize)(this.timerCheckFaxStatus)).EndInit();

            }

            /// <summary>
            /// Clean up any resources being used.
            /// </summary>
            protected override void Dispose( bool disposing )
            {
                  if( disposing )
                  {
                        if (components != null)
                        {
                              components.Dispose();
                        }
                  }
                  base.Dispose( disposing );
            }

            /// <summary>
            /// Set things in motion so your service can do its work.
            /// </summary>
            protected override void OnStart(string[] args)
            {
                  // TODO: Add code here to start your service.
                  this.timerCheckFaxStatus.Enabled=true;
            }

            private Outlook.MAPIFolder GotoFolder(Outlook.MAPIFolder fldr, string FolderName)
            {
                  if (fldr == null ) return null;
                  if (fldr.Name == FolderName) return fldr;
                  foreach(Outlook.MAPIFolder folder in fldr.Folders)
                  {
                        if (folder.DefaultItemType != Outlook.OlItemType.olMailItem)
                              continue;
                        if (folder.Name == FolderName)
                              return folder;
                        Outlook.MAPIFolder f = GotoFolder(folder,FolderName);
                        if (f != null)
                              return f;
                  }
                  return null;
            }


            private void ProcessFailures()
            {
                  string FolderName = "Anekdots";//<=== Folder name you want to open.

                  Outlook.Application oApp;
                  Outlook.NameSpace oNamespace;

                  oApp = new Outlook.ApplicationClass();
                  oNamespace = oApp.GetNamespace("MAPI");
                  oNamespace.Logon(null,null,true,true);
                  //if you have more than one account,get corresponding folder from oNamespace.Folders collection
                  Outlook.MAPIFolder fldr = GotoFolder(oNamespace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox) ,FolderName);
                  if (fldr == null)
                  {
                        gmMessage.AddMessage("IT","Folder Not Found");
                  }

                  if (fldr.DefaultItemType != Outlook.OlItemType.olMailItem )
                  {                        
                        gmMessage.AddMessage("IT","Can't work with non-Mail Items");
                  }


                  foreach(Outlook.MailItem mitem in fldr.Items)
                  {
                        //Here if you running this code from external application you'll get outlook warning "Another program tying to access ... bla-bla-bla... Allow access for 1(2)(5) minute(s)?". You will not recieve this message if you are running in Outlook addin or outlook custom form code.
                        string forParsing = mitem.Body;
                        //<write here parsing code>
                  }
            }

            private void ProcessSuccesses()
            {
            }

            /// <summary>
            /// Stop this service.
            /// </summary>
            protected override void OnStop()
            {
                  // TODO: Add code here to perform any tear-down necessary to stop your service.
            }

            private void timerCheckFaxStatus_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
            {                  
                  try
                  {
                        gmMessage.AddMessage("IT","Inside OnStart just before call to ProcessFailures");
                        ProcessFailures();
                        gmMessage.AddMessage("IT","Inside OnStart just after call to ProcessFailures");
                  }
                  catch(Exception ee)
                  {
                        gmMessage.AddMessage("IT","Exception thrown inside function OnStart.  Message:  " + ee.Message + "::StackTrace:  " + ee.StackTrace);
                        gmMessage.WriteMessagesOutToFile("IT","C:\\faxprogressFAILURE.txt");
                  }            
            }
      }
}

0
 
LVL 5

Author Comment

by:knowlton
ID: 10825076
0
 
LVL 8

Expert Comment

by:RomanPetrenko
ID: 10825869
0
 
LVL 5

Author Comment

by:knowlton
ID: 10826056
I looked at your answer.

It is looking like I am using the wrong code....based on the other posts you have made in my other questions.

Like I said in my other post, I am using Outlook 2000 and VS .NET 2002.
0
 
LVL 8

Expert Comment

by:RomanPetrenko
ID: 10826438
As I said in my first post I gave you sample for outlook 2003, but you can work with it
just change foreach statements:
for(Outlook.MAPIFolder folder = fldr.Folders.GetFirst();folder != null; folder = fldr.Folders.GetNext())
instead of
foreach(Outlook.MAPIFolder folder in fldr.Folders) in GotoFolders
and
for(Outlook.MailItem mitem = fldr.Items.GetFirst();mitem != null; mitem = fldr.Items.GetNext())
instead of
foreach(Outlook.MailItem mitem in fldr.Items)

that's all,

PS: Sorry, I can't check this code, I'm already at home. Try to check this code I'll be waiting for your answers.
0
 
LVL 5

Author Comment

by:knowlton
ID: 10826465
Roman:

You code does not work under VS .NET 2002.....even after converting the foreach statements over to just for loops.
0
 
LVL 8

Expert Comment

by:RomanPetrenko
ID: 10826473
What errors you get?
0
 
LVL 5

Author Comment

by:knowlton
ID: 10826499
Now I am getting:

Inside OnStart just before call to ProcessFailures
Exception thrown inside function OnStart.  Message:  Could not complete the operation because the service provider does not support it.::StackTrace:     at Outlook.NameSpaceClass.GetDefaultFolder(OlDefaultFolders FolderType)
   at WindowsServiceTrackRequestProgress.ServiceTrackRequestProgress.ProcessFailures() in n:\clientdevelopment\neo\buyersfund\windowsservicetrackrequestprogress\servicetrackrequestprogress.cs:line 120
   at WindowsServiceTrackRequestProgress.ServiceTrackRequestProgress.timerCheckFaxStatus_Elapsed(Object sender, ElapsedEventArgs e) in n:\clientdevelopment\neo\buyersfund\windowsservicetrackrequestprogress\servicetrackrequestprogress.cs:line 166
ckrequestprogress.cs:line 166


Here is line 120:

     Outlook.MAPIFolder fldr = GotoFolder(oNamespace.GetDefaultFolder(Outlook.OlDefaultFolders.olFolderInbox) ,FolderName);


Here is line 166:

      ProcessFailures();
0
 
LVL 8

Expert Comment

by:RomanPetrenko
ID: 10826518
and what mail server you connected to?
0
 
LVL 5

Author Comment

by:knowlton
ID: 10826528
Exchange with an Outlook client.
0
 
LVL 8

Expert Comment

by:RomanPetrenko
ID: 10826555
1. try to install .Net ver 1.1 from here:
http://www.microsoft.com/downloads/details.aspx?FamilyId=262D25E3-F589-4842-8157-034D1E7CF3A3&displaylang=en
2. Try to check if you're logged in correctly.(May be open Outlook and after that start your program)
What results do you got?
0
 
LVL 8

Expert Comment

by:RomanPetrenko
ID: 10826614
Take a look here:
http://support.microsoft.com/?kbid=329554
It's exactly your problem, am I right? You have to install hotfix...
0
 
LVL 5

Author Comment

by:knowlton
ID: 10826672
The error message is very close to what I have been getting in VS .NET.......but the cause of the error message seems specific to another problem???????
0
 
LVL 5

Author Comment

by:knowlton
ID: 10826688
If you read carefully the solution page says:

RESOLUTION
A supported fix is now available from Microsoft, but it is only intended to correct the problem that is described in this article. Apply it only to computers that are experiencing this specific problem.


My question is....is the article describing my problem?
0
 
LVL 8

Expert Comment

by:RomanPetrenko
ID: 10826698
But you use API, that they use for reply... so they will not write "When you access Folders property..." they gives sample that every one can understand...
0
 
LVL 5

Author Comment

by:knowlton
ID: 10826708
Okay.  :)
0
 
LVL 8

Expert Comment

by:RomanPetrenko
ID: 10826717
I think this is exactly your problem, try to install hofix.
BTW: They wrote such resolution for each Hotfix they posts, it's politics. And also they include the hotfix into future SP so from this time it's for everyone, strange ?! :)
0
 
LVL 5

Author Comment

by:knowlton
ID: 10826730
Roman:  Good point.  If they are putting the fix in the SP then it is most likely "Okay" for me to apply the hotfix.

Tom
0
 
LVL 5

Author Comment

by:knowlton
ID: 10826737
What is the easiest way to determine what SP my Outlook 2000 is using right now?
0
 
LVL 8

Expert Comment

by:RomanPetrenko
ID: 10826738
But read carefully this article, you should have SP3 installed befor you install hotfix. It's post-SP3.
0
 
LVL 5

Author Comment

by:knowlton
ID: 10826756
I am looking for SP3  (I assume it includes   SP1   and SP2    as well?  )
0
 
LVL 8

Expert Comment

by:RomanPetrenko
ID: 10826761
run Office update:
http://office.microsoft.com/OfficeUpdate/default.aspx it will tell you what you need to install
0
 
LVL 5

Author Comment

by:knowlton
ID: 10827429
Roman:

I just finished installing all of the pending Windows Crititcal Updates.

My code compiles and builds the .EXE just fine, but when I run the Windows Service I get an error file that says:

Inside OnStart just before call to ProcessFailures
Exception thrown inside function OnStart.  Message:  Could not complete the operation because the service provider does not support it.::StackTrace:     at Outlook.NameSpaceClass.GetDefaultFolder(OlDefaultFolders FolderType)
   at WindowsServiceTrackRequestProgress.ServiceTrackRequestProgress.ProcessFailures() in n:\clientdevelopment\neo\buyersfund\windowsservicetrackrequestprogress\servicetrackrequestprogress.cs:line 121
   at WindowsServiceTrackRequestProgress.ServiceTrackRequestProgress.timerCheckFaxStatus_Elapsed(Object sender, ElapsedEventArgs e) in n:\clientdevelopment\neo\buyersfund\windowsservicetrackrequestprogress\servicetrackrequestprogress.cs:line 168
ckrequestprogress.cs:line 166



0
 
LVL 8

Expert Comment

by:RomanPetrenko
ID: 10830433
I think you have problem with Window Service security, What account do you use to run the service?
If you run this code not as service but as windows application - it works?
0
 
LVL 8

Accepted Solution

by:
RomanPetrenko earned 500 total points
ID: 10830719
Look here:
INFO: Outlook Object Model Unsuitable to Run in a Windows Service
http://support.microsoft.com/default.aspx?scid=http://support.microsoft.com:80/support/kb/articles/q237/9/13.asp&NoWebContent=1

so you can't use outlook in Windows Service. and, I think, the sample I gave you should work in windows application.
0
 
LVL 5

Author Comment

by:knowlton
ID: 10834220
Roman:

Agreed.....does not look like Outlook automation would work in a Windows Service.

BUT

What about Exchange Event Sinks?
0
 
LVL 8

Expert Comment

by:RomanPetrenko
ID: 10836656
I think they should work, It's COM+, but I've never used them...
0
 
LVL 5

Author Comment

by:knowlton
ID: 11120018
UPDATE:

Well, guess what?

I finally had a major breakthrough on this @!#$^% problem that has been driving me crazy for the last few weeks!!!!!!!


It is a very small change.

Apparently the method   MoveFirst(   ) does not work so well with Exchange.

This was the cause of my COMException:   "Interface not registered" error message this entire time.


The solution is to use    Move(1,0)     instead of MoveFirst(  ).


That's it.   Simple.

This answer came courtesy of Tom Rizzo, an author who was kind enough to correspond with me and help me figure-out finally what the problem was.:

Looking for a good book on programming Exchange, Outlook, ADSI and
SharePoint?  Check out http://www.microsoft.com/MSPress/books/5517.asp

My I also reommend:

.NET and COM: The Complete Interoperability Guide  ISBN:067232170X
http://www.amazon.ca/exec/obidos/ASIN/067232170X/componentsnot-20/701-9386310-4703553
0
 
LVL 5

Author Comment

by:knowlton
ID: 11120315
More on the MoveFirst problem I described:

http://support.microsoft.com/default.aspx?scid=kb;en-us;273791


If you are getting into Event Sinks....I recommend the following tutorial:

http://www.codeproject.com/csharp/CsManagedEventSinksHooks.asp

Make sure and read the article questions and follow-ups at the bottom!

There are a few caveats.  E-mail me at my Profile e-mail address and we can talk about them.  :)
0

Featured Post

3 Use Cases for Connected Systems

Our Dev teams are like yours. They’re continually cranking out code for new features/bugs fixes, testing, deploying, testing some more, responding to production monitoring events and more. It’s complex. So, we thought you’d like to see what’s working for us.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Article by: Ivo
C# And Nullable Types Since 2.0 C# has Nullable(T) Generic Structure. The idea behind is to allow value type objects to have null values just like reference types have. This concerns scenarios where not all data sources have values (like a databa…
Calculating holidays and working days is a function that is often needed yet it is not one found within the Framework. This article presents one approach to building a working-day calculator for use in .NET.
Microsoft Active Directory, the widely used IT infrastructure, is known for its high risk of credential theft. The best way to test your Active Directory’s vulnerabilities to pass-the-ticket, pass-the-hash, privilege escalation, and malware attacks …
Two types of users will appreciate AOMEI Backupper Pro: 1 - Those with PCIe drives (and haven't found cloning software that works on them). 2 - Those who want a fast clone of their boot drive (no re-boots needed) and it can clone your drive wh…

809 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question