Home All Groups Group Topic Archive Search About

Outlook Message Format Library

Author
13 Dec 2006 1:33 AM
Steven Nagy
Hi all,

I need to be able to take messages that have been saved from Outlook
(*.msg) and read them into a C# application (think of it as workflow
management). But these msg files are pretty funky.
All my research only turned up stuff about Automating Exchange and MAPI
which I know nothing about. I would prefer in this instance to think of
it more as a "black box" scenario where I can have a nice managed
library where I can load a msg file and have nicely exposed properties
about the message. We would then save the important information
(sender, subject, body, importance) to a database table and discard the
actual message file.

I can pay for such a component if it exists, but can develop one with
the right guidance as well.

Can you please provide advice to help me solve my problem?

Many thanks,
Steven Nagy

Author
13 Dec 2006 8:29 AM
KWienhold
Hi Steven,
I had to deal with *.msg files as well a while back. Turns out they are
actually so-called compound files (a single file containing several
streams/subdirectories).
First you need the StgOpenStorage(Ex) function from the ole32.dll to
open these files, then
you can use the IStream/IStorage Interfaces to work with the contents
(IStream is already implemented in the .NET Framework, IStorage
unfortunately isn't).
I can't release the classes I created to work with these messages, but
I can provide you with my IStorage-Interface and StgOpenStorage
definitions, hopefully these will enable you to open the *.msg files
and take a look at their contents.
Its actually pretty straightforward from there, certain properties are
always stored in certain subdirectories/streams, so you need to figure
out the names of the streams you need and read their contents.
For further assistance with the IStream/IStorage interfaces you can
take a look at the msdn, they are pretty well documented.

Sincerely,
Kevin Wienhold

Definitions:

[ComImport,ComVisible(true)]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
[Guid("0000000b-0000-0000-C000-000000000046")]
public interface IStorage
{
    [PreserveSig]
    [return: MarshalAs(UnmanagedType.Error)]
    uint CreateStream(
    [In, MarshalAs(UnmanagedType.LPWStr)] string pwcsName,
    [In]  int grfMode,
    [In]  int reserved1,
    [In]  int reserved2,
    [Out] out UCOMIStream ppstm);


                [PreserveSig]
    [return: MarshalAs(UnmanagedType.Error)]
    uint OpenStream(
    [In, MarshalAs(UnmanagedType.LPWStr)] string pwcsName,
    [In] IntPtr reserved1,
    [In] int grfMode,
    [In] int reserved2,
    [Out] out UCOMIStream ppstm);


    [PreserveSig]
    [return: MarshalAs(UnmanagedType.Error)]
    uint CreateStorage(
    [In, MarshalAs(UnmanagedType.LPWStr)] string pwcsName,
    [In] int grfMode,
    [In] int reserved1,
    [In] int reserved2,
    [Out] out IStorage ppstg);


    [PreserveSig]
    [return: MarshalAs(UnmanagedType.Error)]
    uint OpenStorage(
    [In, MarshalAs(UnmanagedType.LPWStr)] string pwcsName,
    [In, MarshalAs(UnmanagedType.Interface)] IStorage pstgPriority,
    [In] int grfMode,
    [In] string[] snbExclude,
    [In] int reserved,
    [Out] out IStorage ppstg);


    [PreserveSig]
    [return: MarshalAs(UnmanagedType.Error)]
    uint CopyTo(
    [In] int ciidExclude,
    [In] Guid[] rgiidExclude,
    [In] string[] snbExclude,
    [In, MarshalAs(UnmanagedType.Interface)] IStorage pstgDest);


    [PreserveSig]
    [return: MarshalAs(UnmanagedType.Error)]
    uint MoveElementTo(
    [In, MarshalAs(UnmanagedType.LPWStr)] string pwcsName,
    [In, MarshalAs(UnmanagedType.Interface)] IStorage pstgDest,
    [In, MarshalAs(UnmanagedType.LPWStr)] string pwcsNewName,
    [In] int grfFlags);


    [PreserveSig]
    [return: MarshalAs(UnmanagedType.Error)]
    uint Commit(
    [In] int grfCommitFlags);


    [PreserveSig]
    [return: MarshalAs(UnmanagedType.Error)]
    uint Revert();


    [PreserveSig]
    [return: MarshalAs(UnmanagedType.Error)]
    uint EnumElements(
    [In] int reserved1,
    [In] IntPtr reserved2,
    [In] int reserved3,
    [Out] out IEnumSTATSTG ppenum);


    [PreserveSig]
    [return: MarshalAs(UnmanagedType.Error)]
    uint DestroyElement(
    [In, MarshalAs(UnmanagedType.LPWStr)] string pwcsName);


    [PreserveSig]
    [return: MarshalAs(UnmanagedType.Error)]
    uint RenameElement(
    [In, MarshalAs(UnmanagedType.LPWStr)] string pwcsOldName,
    [In, MarshalAs(UnmanagedType.LPWStr)] string pwcsNewName);


    [PreserveSig]
    [return: MarshalAs(UnmanagedType.Error)]
    uint SetElementTimes(
    [In, MarshalAs(UnmanagedType.LPWStr)] string pwcsName,
    [In] ref FILETIME pctime,
    [In] ref FILETIME patime,
    [In] ref FILETIME  pmtime);


    [PreserveSig]
    [return: MarshalAs(UnmanagedType.Error)]
    uint SetClass(
    [In] ref Guid clsid);


    [PreserveSig]
    [return: MarshalAs(UnmanagedType.Error)]
    uint SetStateBits(
    [In] uint grfStateBits,
    [In] uint grfMask);


    [PreserveSig]
    [return: MarshalAs(UnmanagedType.Error)]
    uint Stat(
    [Out] out STATSTG pstatstg,
    [In]  uint grfStatFlag);



}


[DllImport("Ole32.dll")]
private static extern int StgOpenStorage
(
    [MarshalAs(UnmanagedType.LPWStr)] string wcsName,
    IStorage pstgPriority,
    int grfMode,              // access method
    IntPtr snbExclude,        // must be NULL
    int    reserved,         // reserved
    out IStorage storage    // returned storage
);

Steven Nagy schrieb:

Show quoteHide quote
> Hi all,
>
> I need to be able to take messages that have been saved from Outlook
> (*.msg) and read them into a C# application (think of it as workflow
> management). But these msg files are pretty funky.
> All my research only turned up stuff about Automating Exchange and MAPI
> which I know nothing about. I would prefer in this instance to think of
> it more as a "black box" scenario where I can have a nice managed
> library where I can load a msg file and have nicely exposed properties
> about the message. We would then save the important information
> (sender, subject, body, importance) to a database table and discard the
> actual message file.
>
> I can pay for such a component if it exists, but can develop one with
> the right guidance as well.
>
> Can you please provide advice to help me solve my problem?
>
> Many thanks,
> Steven Nagy
Are all your drivers up to date? click for free checkup

Author
13 Dec 2006 8:49 PM
Steven Nagy
Thanks Kevin. This is definately a good place for me to start.
Great well rounded response!


KWienhold wrote:
Show quoteHide quote
> Hi Steven,
> I had to deal with *.msg files as well a while back. Turns out they are
> actually so-called compound files (a single file containing several
> streams/subdirectories).
> First you need the StgOpenStorage(Ex) function from the ole32.dll to
> open these files, then
> you can use the IStream/IStorage Interfaces to work with the contents
> (IStream is already implemented in the .NET Framework, IStorage
> unfortunately isn't).
> I can't release the classes I created to work with these messages, but
> I can provide you with my IStorage-Interface and StgOpenStorage
> definitions, hopefully these will enable you to open the *.msg files
> and take a look at their contents.
> Its actually pretty straightforward from there, certain properties are
> always stored in certain subdirectories/streams, so you need to figure
> out the names of the streams you need and read their contents.
> For further assistance with the IStream/IStorage interfaces you can
> take a look at the msdn, they are pretty well documented.
>
> Sincerely,
> Kevin Wienhold
>
> Definitions:
>
> [ComImport,ComVisible(true)]
> [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
> [Guid("0000000b-0000-0000-C000-000000000046")]
> public interface IStorage
> {
>     [PreserveSig]
>     [return: MarshalAs(UnmanagedType.Error)]
>     uint CreateStream(
>     [In, MarshalAs(UnmanagedType.LPWStr)] string pwcsName,
>     [In]  int grfMode,
>     [In]  int reserved1,
>     [In]  int reserved2,
>     [Out] out UCOMIStream ppstm);
>
>
>                 [PreserveSig]
>     [return: MarshalAs(UnmanagedType.Error)]
>     uint OpenStream(
>     [In, MarshalAs(UnmanagedType.LPWStr)] string pwcsName,
>     [In] IntPtr reserved1,
>     [In] int grfMode,
>     [In] int reserved2,
>     [Out] out UCOMIStream ppstm);
>
>
>     [PreserveSig]
>     [return: MarshalAs(UnmanagedType.Error)]
>     uint CreateStorage(
>     [In, MarshalAs(UnmanagedType.LPWStr)] string pwcsName,
>     [In] int grfMode,
>     [In] int reserved1,
>     [In] int reserved2,
>     [Out] out IStorage ppstg);
>
>
>     [PreserveSig]
>     [return: MarshalAs(UnmanagedType.Error)]
>     uint OpenStorage(
>     [In, MarshalAs(UnmanagedType.LPWStr)] string pwcsName,
>     [In, MarshalAs(UnmanagedType.Interface)] IStorage pstgPriority,
>     [In] int grfMode,
>     [In] string[] snbExclude,
>     [In] int reserved,
>     [Out] out IStorage ppstg);
>
>
>     [PreserveSig]
>     [return: MarshalAs(UnmanagedType.Error)]
>     uint CopyTo(
>     [In] int ciidExclude,
>     [In] Guid[] rgiidExclude,
>     [In] string[] snbExclude,
>     [In, MarshalAs(UnmanagedType.Interface)] IStorage pstgDest);
>
>
>     [PreserveSig]
>     [return: MarshalAs(UnmanagedType.Error)]
>     uint MoveElementTo(
>     [In, MarshalAs(UnmanagedType.LPWStr)] string pwcsName,
>     [In, MarshalAs(UnmanagedType.Interface)] IStorage pstgDest,
>     [In, MarshalAs(UnmanagedType.LPWStr)] string pwcsNewName,
>     [In] int grfFlags);
>
>
>     [PreserveSig]
>     [return: MarshalAs(UnmanagedType.Error)]
>     uint Commit(
>     [In] int grfCommitFlags);
>
>
>     [PreserveSig]
>     [return: MarshalAs(UnmanagedType.Error)]
>     uint Revert();
>
>
>     [PreserveSig]
>     [return: MarshalAs(UnmanagedType.Error)]
>     uint EnumElements(
>     [In] int reserved1,
>     [In] IntPtr reserved2,
>     [In] int reserved3,
>     [Out] out IEnumSTATSTG ppenum);
>
>
>     [PreserveSig]
>     [return: MarshalAs(UnmanagedType.Error)]
>     uint DestroyElement(
>     [In, MarshalAs(UnmanagedType.LPWStr)] string pwcsName);
>
>
>     [PreserveSig]
>     [return: MarshalAs(UnmanagedType.Error)]
>     uint RenameElement(
>     [In, MarshalAs(UnmanagedType.LPWStr)] string pwcsOldName,
>     [In, MarshalAs(UnmanagedType.LPWStr)] string pwcsNewName);
>
>
>     [PreserveSig]
>     [return: MarshalAs(UnmanagedType.Error)]
>     uint SetElementTimes(
>     [In, MarshalAs(UnmanagedType.LPWStr)] string pwcsName,
>     [In] ref FILETIME pctime,
>     [In] ref FILETIME patime,
>     [In] ref FILETIME  pmtime);
>
>
>     [PreserveSig]
>     [return: MarshalAs(UnmanagedType.Error)]
>     uint SetClass(
>     [In] ref Guid clsid);
>
>
>     [PreserveSig]
>     [return: MarshalAs(UnmanagedType.Error)]
>     uint SetStateBits(
>     [In] uint grfStateBits,
>     [In] uint grfMask);
>
>
>     [PreserveSig]
>     [return: MarshalAs(UnmanagedType.Error)]
>     uint Stat(
>     [Out] out STATSTG pstatstg,
>     [In]  uint grfStatFlag);
>
>
>
> }
>
>
> [DllImport("Ole32.dll")]
> private static extern int StgOpenStorage
> (
>     [MarshalAs(UnmanagedType.LPWStr)] string wcsName,
>     IStorage pstgPriority,
>     int grfMode,              // access method
>     IntPtr snbExclude,        // must be NULL
>     int    reserved,         // reserved
>     out IStorage storage    // returned storage
> );
>
> Steven Nagy schrieb:
>
> > Hi all,
> >
> > I need to be able to take messages that have been saved from Outlook
> > (*.msg) and read them into a C# application (think of it as workflow
> > management). But these msg files are pretty funky.
> > All my research only turned up stuff about Automating Exchange and MAPI
> > which I know nothing about. I would prefer in this instance to think of
> > it more as a "black box" scenario where I can have a nice managed
> > library where I can load a msg file and have nicely exposed properties
> > about the message. We would then save the important information
> > (sender, subject, body, importance) to a database table and discard the
> > actual message file.
> >
> > I can pay for such a component if it exists, but can develop one with
> > the right guidance as well.
> >
> > Can you please provide advice to help me solve my problem?
> >
> > Many thanks,
> > Steven Nagy

Bookmark and Share