Loading outlook's MSG files from disk into outlook

ebi1
ebi1 used Ask the Experts™
on
hi all

how can i read\load MSG files of Outlook into a specific folder in outlook?
i don't need to view them. just to load them in.

example:
i have the file and path : "c:\ebi\TempZ\66.msg"
and i want to put it in the folder "ebi\ZZZ" which is inside the "Personal Folders" of outlook
(of course with the attachments)

i'm using outlook2003 and Delphi6
many thanks for your help
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
Most Valuable Expert 2011
Top Expert 2011

Commented:
You can simply drag them into a folder in Outlook, unless you are trying to do this programmatically......

:^)

Author

Commented:
thanks for your reply johnb6767
i know about what you wrote, but i'm trying to do that programmatically with Delphi
it's a part of a program that read and write mails to/from the disk.

i would do it manually if it wasn't for 1700 users who have about 5000 mails each....  :D
Top Expert 2007

Commented:
you will need to use outlook extended MAPI or some componets/library that does it for you.
afetr searching on the net I found something, but not tested:
- http://delphi.about.com/od/kbcontrolole/l/aa110403a.htm (I know it's about contacts, but maybe the compoents used also support emails...)
- http://www.imibo.com/imidev/delphi/les/index.html more exactly: http://www.imibo.com/imidev/delphi/les/index_3.html 
- http://anti-crisis-software.com/airmailsdk.html (kind of expensive though)
- this PAQ might also help: http://www.experts-exchange.com/Programming/Languages/Pascal/Delphi/Q_23072224.html
Success in ‘20 With a Profitable Pricing Strategy

Do you wonder if your IT business is truly profitable or if you should raise your prices? Learn how to calculate your overhead burden using our free interactive tool and use it to determine the right price for your IT services. Start calculating Now!

Author

Commented:
ciuly,
thank you for your replay
i'm still checking, testing and playing around with what you wrote
Russell LibbySoftware Engineer, Advisory
Top Expert 2005

Commented:

My suggestion would be to use Redemption Objects. Otherwise, the only direct alternative would be to use extended MAPI (not fun, and not easy). If you are doing this as a commerical project, then it will cost you a one time fee of $199. When you weight this with the time factor of trying to write the MapiX routines yourself, you will probably find this to be a bargain.

Anyways, here is a sample project based on Redemption that does the desired import. Gives you an idea of what needs to be done (and lets you verify that it does work).

Regards,
Russell

--- project source ---
unit Test;
////////////////////////////////////////////////////////////////////////////////
//
//   Redemption Info
//
//   Home        :  http://www.dimastr.com/redemption/
//   Download    :  http://www.dimastr.com/redemption/Redemption.zip
//   Notes       :  If you plan on distributing this as a commercial project,
//                  you will need to purchase a license from www.dimastr.com.
//
////////////////////////////////////////////////////////////////////////////////
interface

////////////////////////////////////////////////////////////////////////////////
//   Compiler defines
////////////////////////////////////////////////////////////////////////////////

  {$IFDEF VER140} { Borland Delphi 6.0 }
     {$DEFINE DELPHI_6_ABOVE}
  {$ENDIF}

  {$IFDEF VER150} { Borland Delphi 7.0 }
     {$DEFINE DELPHI_6_ABOVE}
  {$ENDIF}

  {$IFDEF VER160} { Borland Delphi 8.0 }
     {$DEFINE DELPHI_6_ABOVE}
  {$ENDIF}

  {$IFDEF VER170} { Borland Delphi 2005 }
     {$DEFINE DELPHI_6_ABOVE}
  {$ENDIF}

  {$IFDEF VER180} { Borland Delphi 2007 }
     {$DEFINE DELPHI_6_ABOVE}
  {$ENDIF}

  {$IFDEF VER185} { Borland Delphi 2007 }
     {$DEFINE DELPHI_6_ABOVE}
  {$ENDIF}

  {$IFDEF VER190} { Borland Delphi 2009 }
     {$DEFINE DELPHI_6_ABOVE}
  {$ENDIF}

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  {$IFDEF DELPHI_6_ABOVE} Variants, {$ENDIF} ComObj, ActiveX, StdCtrls,
  ComCtrls;

////////////////////////////////////////////////////////////////////////////////
//   Constants for Redemption
////////////////////////////////////////////////////////////////////////////////
const
  olMailItem              =  $00000000;
  olPostItem              =  $00000006;
  olMsg                   =  $00000003;

////////////////////////////////////////////////////////////////////////////////
//   Callback type
////////////////////////////////////////////////////////////////////////////////
type
  TMsgImport        =  procedure(Index, TotalCount: Integer; var Cancel: Boolean) of object;

////////////////////////////////////////////////////////////////////////////////
//
//   Function    :  MsgImportFileSpec
//
//   Parameters  :  FileSpec
//                  -   file specification to match the desired .msg file(s)
//                  PublicFolderPath
//                  -  folder path in Outlook to import the .msg files into
//                  Callback
//                  -  method to call when a .msg file is imported
//
//   Returns     :  Number of .msg files imported.
//
//   Examples    :
//
//      MsgImportFileSpec('c:\ebi\tempz\*.msg', '\\Personal Folders\ebi\zzz', OnMsgImport);
//      MsgImportFileSpec('c:\ebi\tempz\66.msg', '\\Personal Folders\ebi\zzz', nil);
//
////////////////////////////////////////////////////////////////////////////////
function MsgImportFileSpec(FileSpec: String; PublicFolderPath: String; Callback: TMsgImport): Integer;

type
  TForm1            =  class(TForm)
     btnImport:     TButton;
     btnCancel:     TButton;
     pbImport:      TProgressBar;
     procedure      btnImportClick(Sender: TObject);
     procedure      btnCancelClick(Sender: TObject);
  private
     // Private declarations
     FCancel:       Boolean;
  protected
     // Protected declarations
     procedure      OnMsgImport(Index, TotalCount: Integer; var Cancel: Boolean);
  public
     // Public declarations
  end;

var
  Form1:            TForm1;

implementation
{$R *.DFM}

////////////////////////////////////////////////////////////////////////////////
//
//   Function    :  MsgImportFileSpec
//
//   Parameters  :  FileSpec
//                  -   file specification to match the desired .msg file(s)
//                  PublicFolderPath
//                  -  folder path in Outlook to import the .msg files into
//                  Callback
//                  -  method to call when a .msg file is imported
//
//   Returns     :  Number of .msg files imported.
//
//   Examples    :
//
//      MsgImportFileSpec('c:\ebi\tempz\*.msg', '\\Personal Folders\ebi\zzz');
//      MsgImportFileSpec('c:\ebi\tempz\66.msg', '\\Personal Folders\ebi\zzz');
//
////////////////////////////////////////////////////////////////////////////////
function MsgImportFileSpec(FileSpec: String; PublicFolderPath: String; Callback: TMsgImport): Integer;
var  ovSession:     OleVariant;
     ovFolder:      OleVariant;
     olItem:        OleVariant;
     listFind:      TStringList;
     dwIndex:       Integer;
     bCancel:       Boolean;
     srFind:        TSearchRec;
     szPath:        String;
begin

  // Set default result
  result:=0;

  // Create string list
  listFind:=TStringList.Create;

  // Resource protection
  try
     // Initialize the file find
     if (FindFirst(FileSpec, faAnyFile, srFind) = 0) then
     begin
        // Get the file path
        szPath:=IncludeTrailingBackSlash(ExtractFilePath(FileSpec));
        // Resource protection
        try
           // Repeat while we have files
           repeat
              // Check file extension
              if (CompareText(ExtractFileExt(srFind.Name), '.msg') = 0) then
              begin
                 // Add fully qualified .msg file name to the list
                 listFind.Add(szPath + srFind.Name);
              end;
           // Find next
           until (FindNext(srFind) <> 0);
        finally
           // Close the find
           FindClose(srFind);
        end;
     end;
     // Check list of files to import
     if (listFind.Count > 0) then
     begin
        // Create session
        ovSession:=CreateOleObject('Redemption.RDOSession');
        // Resource protection
        try
           // Logon
           ovSession.Logon;
           // Get folder from path
           ovFolder:=ovSession.GetFolderFromPath(PublicFolderPath);
           // Resource protection
           try
              // Walk the mail items
              for dwIndex:=0 to Pred(listFind.Count) do
              begin
                 // Create a new mail item
                 olItem:=ovFolder.Items.Add(olPostItem);
                 // Resource protection
                 try
                    // Import from msg file
                    olItem.Import(listFind[dwIndex], olMsg);
                    // Move to public folder
                    olItem.Move(ovFolder);
                    // Save item
                    olItem.Save;
                    // Check callback
                    if Assigned(Callback) then
                    begin
                       // Set cancel flag
                       bCancel:=False;
                       // Callback
                       Callback(dwIndex, listFind.Count, bCancel);
                       // If the user cancelled the import then we should break out
                       if bCancel then break;
                    end;
                 finally
                    // Release interface
                    olItem:=Unassigned;
                 end;
              end;
           finally
              // Release interface
              ovFolder:=Unassigned;
           end;
        finally
           // Release interface
           ovSession:=Unassigned;
        end;
     end;
  finally
     // Free the list
     listFind.Free;
  end;

end;

procedure TForm1.btnImportClick(Sender: TObject);
var  dwMark:        LongWord;
begin

  // Clear import progress bar
  pbImport.Min:=0;
  pbImport.Max:=0;
  pbImport.Position:=0;

  // Set button state
  btnImport.Enabled:=False;
  btnCancel.Enabled:=True;

  // Resource protection
  try
     // Set cancel flag
     FCancel:=False;
     // Start the import
     MsgImportFileSpec('c:\ebi\tempz\*.msg', '\\Personal Folders\ebi\zzz', OnMsgImport);
  finally
     // Set button state
     btnImport.Enabled:=True;
     btnCancel.Enabled:=False;
  end;

end;

procedure TForm1.OnMsgImport(Index, TotalCount: Integer; var Cancel: Boolean);
begin

  // Set progress bar state
  pbImport.Min:=0;
  pbImport.Max:=TotalCount;
  pbImport.Position:=Succ(Index);

  // Resource protection
  try
     // Process message
     Application.ProcessMessages;
  finally
     // Set cancel flag
     Cancel:=FCancel;
  end;

end;

procedure TForm1.btnCancelClick(Sender: TObject);
begin

  // Set cancel flag
  FCancel:=True;

end;

end.

--- form dfm ---
object Form1: TForm1
  Left = 340
  Top = 370
  Width = 563
  Height = 165
  Caption = 'Form1'
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  OldCreateOrder = False
  PixelsPerInch = 96
  TextHeight = 13
  object btnImport: TButton
    Left = 12
    Top = 20
    Width = 75
    Height = 25
    Caption = 'Import'
    TabOrder = 0
    OnClick = btnImportClick
  end
  object pbImport: TProgressBar
    Left = 12
    Top = 52
    Width = 501
    Height = 17
    Min = 0
    Max = 100
    TabOrder = 1
  end
  object btnCancel: TButton
    Left = 92
    Top = 20
    Width = 75
    Height = 25
    Caption = 'Cancel'
    TabOrder = 2
    OnClick = btnCancelClick
  end
end


Author

Commented:
many thanks for your help guys.
i have found a way to do it only with Delphi and outlook (no 3rd party components)

i just needed to write a mail to the disk, do something and then read it back into the outlook, so after using ItemOL.SaveAs(MyPathAndFile) and made a .MSG file, i used CreateItemFromTemplate(MyPathAndFile)

however, i couldn't find, how to make my Default Folder be the one i really want(e.g. "ebi\ZZZ")

so what i did was this :
ItemOL:=Outlook.CreateItemFromTemplate(MyPathAndFile, Folder);

//Outlook will save it to the default folder - "Drafts" because i didn't set the Default Folder
ItemOL.Save;

//And then i need to move it to it's original Folder
ItemOL.Move(Folder);

i don't know exactly how it works, but for now, i just need it to run.
so i don't care much about it's efficiency.

BUT...
if you save the mail to the disk using Outlook 2003, it's NOT saving the Sender's name and the Recieved time of the mail item.
these 2 properties are ReadOnly, so you will not be able to set them...

it is fixed and NOT ReadOnly in Outlook 2007, so when you save it to the disk it is really the EXACT same mail.

Author

Commented:
btw

airmailsdk and Redemption cost 200$-300$, which i dont have for that, so...

ciuly, i checked your links and as far as i could understand, working on Contacts in outlook, is not the same as working on mails.
i used the Outlook2000.pas to check inside.
and i'm no expert in ADO, but i think using ADO with what i did in my program, would confuse me even more.
and altho i needed something else, the imibo.com/imidev/delphi/les/index_3.html link you posted is really greate, so i saved it anyway.

rllibby, i'm really sorry to say that after everything you wrote, but i have to go back to the price of the Redemption(300$ without the source, or 800$ with source...)

and now i don't know how to close this question.
i dont want to delete it, because i want it to help others with the same problem,
and on the other hand, i got the answer, but i dont want to "award" myself...
so how can i close the question without deleting it?

i REALLY appreciate your effort and help guys.
many thanks for your time and ideas
Top Expert 2007

Commented:
I didn't quite understand what you said: I are using redemtion in the end or not? if so, then award russel the points, since he mentioned it. if not, what is it that solved it? (not for me, for future reference).

regarding closing: you can close the question by accepting your post as answer. there should be a link in your post. that will start the automatic closing procedure by PAQ on your answer and points refunded if I recall correctly.

Commented:
hi ciuly
i didn't use the Redemption because it is too expansive for me.

i used only functions/procedures from the Outlook2000.pas that comes with Delphi
(i use Delphi 6 Ent)

what solved it this:

uses OleServer

Var outlook, NameSpace, Folder, ItemOL : OLEVariant;
Begin
  outlook := CreateOleObject('Outlook.Application');
  NameSpace := outlook.GetNameSpace('MAPI');
  Folder := NameSpace.GetFolderFromID(PString(tvFolders.Selected.Data)^);//taken from a treeview

  ItemOL:=Outlook.CreateItemFromTemplate(MyPathAndFile, Folder);//  <<====  that's THE big point

  //Outlook will save it to the default folder - "Drafts" because i didn't set the Default Folder
  ItemOL.Save;

  //And then i need to move it back to it's original Folder (the folder was taken from a treeview)
  ItemOL.Move(Folder);

  outlook := UnAssigned;
End;

i would be happy to answer every question about this, but i'm not even sure i understand it correctly...lol
anyway, it's working  :)
Top Expert 2007

Commented:
I'm glad it's working :)

Author

Commented:
oops...
i meant :

uses ComObj;

sorry

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial