Solved

Outlook plug-in Save Email to hard drive

Posted on 2006-06-13
10
378 Views
Last Modified: 2008-03-10
Very important to my company.  I need to have a plug-in that saves a specific outgoing email based on recipient to a text file on the hard drive before it is sent.  It could be saved while it is being sent also.

What would be great if I can also get an example of the same but for incoming from a certain recipient.  I would like code instead of using the Rules Wizard.  I'm using POP and not Exchange.
0
Comment
Question by:famoso
  • 5
  • 4
10 Comments
 
LVL 14

Expert Comment

by:existenz2
ID: 16894273
You could use VSTO (Visual Studio Tools for Office) or Information Worker to solve your problem. If you are using Office 2003 a final solution would be creating an application which uses the .NET Office 2003 library (Default installed with Office 2003 Prof.), but I would suggest VSTO or IW.
0
 
LVL 2

Expert Comment

by:bdsmithback
ID: 16900015
You're probably going to want to create an add-in for Outlook.  

Here's a place to start with Office Add-ins: http://support.microsoft.com/?kbid=302901

Here's some specific information on Oultook: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dv_vstechart/html/ol03csharp.asp

Once you have an add-in for Outlook, the code is pretty straightforward.  Capture the ItemSend event in the Application class and save the messages.  Here's an incomplete example - but it should get the job done.

void Connect_ItemSend(object Item, ref bool Cancel)
{
      try
      {
            ((Outlook.MailItem)Item).SaveAs("c:\\somepath\\somefile.msg", (object)Outlook.OlSaveAsType.olMSG);
      }
      catch { }
}

One final thought.  If this is going to be distributed to a lot of people - you may want to consider using a shim for your COM addin.  Office doesn't play well with managed code and a shim can help with that.

Good luck!

0
 

Author Comment

by:famoso
ID: 16901644
I just found what I was looking for ... almost.  The problem is I don't want the code exposed if an error appears and also it should be easily maintained (as in one DLL) so I can make just one change and not many changes if for example I need the email changed to something else.

-------------------------------------------------------------------------------
Private Sub Application_ItemSend(ByVal Item As Object, Cancel As Boolean)
On Error GoTo End_Application_ItemSend

If Item.Recipients(1).Address = "email@email.com" Then
Open "c:\system.txt" For Append As #1
    Print #1, Now
    Print #1, "Subject: " & Item.Subject
    Print #1, "Body: " & Item.Body
Close #1
End If

End_Application_ItemSend:
Exit Sub

End Sub
-------------------------------------------------------------------------------

The problem is I want the business part to be in a DLL and referenced something like:

Private Sub Application_ItemSend(ByVal Item As Object, Cancel As Boolean)
On Error GoTo End_Application_ItemSend

    dim x as object
    x=createobject("somedll.dll")  ' The DLL can be in VB or C# but probably a COM, right?
    x.somefunction(Item)

End_Application_ItemSend:
Exit Sub

End Sub

Is a plug-in still what I want?  I don't want a menu added to the Outlook IDE I just want my 'DLL' to run when this event is fired.
0
Free Tool: ZipGrep

ZipGrep is a utility that can list and search zip (.war, .ear, .jar, etc) archives for text patterns, without the need to extract the archive's contents.

One of a set of tools we're offering as a way to say thank you for being a part of the community.

 

Author Comment

by:famoso
ID: 16901655
BTW I'm using Outlook 2000
0
 
LVL 2

Expert Comment

by:bdsmithback
ID: 16902650
It's arguable - but I still think a plugin is the way to go.  In Outlook 2002 and up, the Outlook Object Model is protected from programs doing what you're trying to do.  When you capture the ItemSend event from an application running outside of outlook, it pops up a security warning stating that a program is trying to access your e-mail.  If you plan on ever upgrading to 2002 or 2003, a plugin is probably the best way to go.

The other issue is that you will attach to an instance of Oulook.  If that instance is closed and a new one reopened, your event is no going to fire.  There are ways around this, but a plugin solves the problem because it launches with each instance of Outlook.  

From there, you can load an external assembly so it's easy to change.  Here is some info on doing that: http://msdn2.microsoft.com/en-us/library/ky3942xh.aspx

Cheers,
Beau
0
 

Author Comment

by:famoso
ID: 16903772
Can I still, through a plug-in, hijack the Application_ItemSend event or similar???
0
 

Author Comment

by:famoso
ID: 16903855
I'm feeling stupid.  Heres my initial addin code from the wizard ...
Where do I put the code I want to execute?

namespace OutlookPlugin
{
      using System;
      using Microsoft.Office.Core;
      using Extensibility;
      using System.Runtime.InteropServices;
      

      #region Read me for Add-in installation and setup information.
      // When run, the Add-in wizard prepared the registry for the Add-in.
      // At a later time, if the Add-in becomes unavailable for reasons such as:
      //   1) You moved this project to a computer other than which is was originally created on.
      //   2) You chose 'Yes' when presented with a message asking if you wish to remove the Add-in.
      //   3) Registry corruption.
      // you will need to re-register the Add-in by building the MyAddin21Setup project
      // by right clicking the project in the Solution Explorer, then choosing install.
      #endregion
      
      /// <summary>
      ///   The object for implementing an Add-in.
      /// </summary>
      /// <seealso class='IDTExtensibility2' />
      [GuidAttribute("AFE16BFD-BC11-4263-A437-CD70EBDC5CC0"), ProgId("OutlookPlugin.Connect")]
      public class Connect : Object, Extensibility.IDTExtensibility2
      {
            /// <summary>
            ///            Implements the constructor for the Add-in object.
            ///            Place your initialization code within this method.
            /// </summary>
            public Connect()
            {
            }

            /// <summary>
            ///      Implements the OnConnection method of the IDTExtensibility2 interface.
            ///      Receives notification that the Add-in is being loaded.
            /// </summary>
            /// <param term='application'>
            ///      Root object of the host application.
            /// </param>
            /// <param term='connectMode'>
            ///      Describes how the Add-in is being loaded.
            /// </param>
            /// <param term='addInInst'>
            ///      Object representing this Add-in.
            /// </param>
            /// <seealso class='IDTExtensibility2' />
            public void OnConnection(object application, Extensibility.ext_ConnectMode connectMode, object addInInst, ref System.Array custom)
            {
                  
                  
                  applicationObject = application;
                  addInInstance = addInInst;
            }

            /// <summary>
            ///     Implements the OnDisconnection method of the IDTExtensibility2 interface.
            ///     Receives notification that the Add-in is being unloaded.
            /// </summary>
            /// <param term='disconnectMode'>
            ///      Describes how the Add-in is being unloaded.
            /// </param>
            /// <param term='custom'>
            ///      Array of parameters that are host application specific.
            /// </param>
            /// <seealso class='IDTExtensibility2' />
            public void OnDisconnection(Extensibility.ext_DisconnectMode disconnectMode, ref System.Array custom)
            {
            }

            /// <summary>
            ///      Implements the OnAddInsUpdate method of the IDTExtensibility2 interface.
            ///      Receives notification that the collection of Add-ins has changed.
            /// </summary>
            /// <param term='custom'>
            ///      Array of parameters that are host application specific.
            /// </param>
            /// <seealso class='IDTExtensibility2' />
            public void OnAddInsUpdate(ref System.Array custom)
            {
            }

            /// <summary>
            ///      Implements the OnStartupComplete method of the IDTExtensibility2 interface.
            ///      Receives notification that the host application has completed loading.
            /// </summary>
            /// <param term='custom'>
            ///      Array of parameters that are host application specific.
            /// </param>
            /// <seealso class='IDTExtensibility2' />
            public void OnStartupComplete(ref System.Array custom)
            {
            }

            /// <summary>
            ///      Implements the OnBeginShutdown method of the IDTExtensibility2 interface.
            ///      Receives notification that the host application is being unloaded.
            /// </summary>
            /// <param term='custom'>
            ///      Array of parameters that are host application specific.
            /// </param>
            /// <seealso class='IDTExtensibility2' />
            public void OnBeginShutdown(ref System.Array custom)
            {
            }
            
            
            private object applicationObject;
            private object addInInstance;
      }
}
0
 
LVL 2

Accepted Solution

by:
bdsmithback earned 500 total points
ID: 16907715
Sorry for the delay famoso - I've been in meetings all day.  Don't feel stupid - this is not all that intuitive...

Here is the code I think you're looking for.  You're going to want to place the code to capture the ItemSend event in the connect class as that loads when outlook is loading.


//I've changed the type of applicationObject form object to Outlook.Application for ease since this is an outlook only app.
private Outlook.Application applicationObject;

private object addInInstance;
public void OnConnection(object application, Extensibility.ext_ConnectMode connectMode, object addInInst, ref System.Array custom)
{
      applicationObject = (Outlook.Application)application;  //Cast application and Outlook.Application to handle the change from object
      addInInstance = addInInst;

      //Add this event handler
      applicationObject.ItemSend += new Outlook.ApplicationEvents_ItemSendEventHandler(applicationObject_ItemSend);
}

//this handes the ItemSend event
void applicationObject_ItemSend(object Item, ref bool Cancel)
{
      //Add your code here to write the info to the file.
      //I've added some code to access the common fields of the mail item.
      try
      {
            Outlook.MailItem mi = (Outlook.MailItem)Item;
            string subject = mi.Subject;
            string body = mi.Body;
            string to = mi.To;
      }
      catch { }
}

So - to recap: You're adding an event handler on the OnConnection method for Outlook.Application.ItemSend.  You're then adding the code to save the e-mail's content to a file in the application_ItemSend event handler method.  You might also be able to use System.Relfection.Assembly.Load to load another DLL like you talked about, but I've not done this from an addin so I can't promise results.  My guess is that it will work - but I'm not sure how the object model security of outlook will see that...

I hope this helps!

Beau
0
 

Author Comment

by:famoso
ID: 16911193
I'll try that but I definatly understand it better.

So basically in thoughts of defining an event handler, placing applicationObject_ItemSend() in a module in VBA and defining applicationObject_ItemSend() as an event handler in a plugin is the same thing?
0
 
LVL 2

Expert Comment

by:bdsmithback
ID: 16912993
Yes - you can think of it in those terms.  Thanks famoso!
0

Featured Post

Announcing the Most Valuable Experts of 2016

MVEs are more concerned with the satisfaction of those they help than with the considerable points they can earn. They are the types of people you feel privileged to call colleagues. Join us in honoring this amazing group of Experts.

Question has a verified solution.

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

Extention Methods in C# 3.0 by Ivo Stoykov C# 3.0 offers extension methods. They allow extending existing classes without changing the class's source code or relying on inheritance. These are static methods invoked as instance method. This…
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…
Finds all prime numbers in a range requested and places them in a public primes() array. I've demostrated a template size of 30 (2 * 3 * 5) but larger templates can be built such 210  (2 * 3 * 5 * 7) or 2310  (2 * 3 * 5 * 7 * 11). The larger templa…

856 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