Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Outlook 2003, OLE, MAPI, ARGH!! Its all gone bananas

Status
Not open for further replies.

perltastic

Programmer
Sep 16, 2004
4
GB
Can someone shed any light or direction to explore the issue I'm facing. Until recently I have been using a script that I wrote to send message via Outlook XP. It has been running smoothly for months. Then the IT department decided it would be good idea to upgrade everyone's meachine to MS Office 2003 (including Outlook 2003) and now the script doesn't work.

The error I get is

Failed to create a new MAPI Session! at domail.pl line 178.
A thread exited while 2 threads were running.

I looked at the list of packages installed using ppm and found that Win32-OLE was not listed. So I installed it and since then it has got worse. The error now is

Win32::OLE(0.1403) error 0x800401f3: "Invalid class string" at domail.pl line 178
eval {...} called at domail.pl line 178
main::main() called at domail.pl line 233
Failed to create a new MAPI Session! at domail.pl line 178.
A thread exited while 2 threads were running.

The code is listed below. Much of it is in the public domain so there should be no surprises. Having said that, I'm no Perl expert so its likely to be riddled with bugs.

Code below....

Code:
#! c:\perl\bin\perl
#
# This script sends email via Outlook and MS Exchange and works around the MS service pack security update
# So now you don't need outlook running and you don't have to press a button to complete sending the mail.
# The code is based on one found at the perlmonks forum. The one on the forum had some bugs and did not work for me
# as stated with the security prompts.
#
# Created by: me
#
# Usage:
#               perl domail.pl <options>
#               <options>: (M) = Mandetory; (O) = Optional
#
#               --email     (M) target email address in full
#               --to        (M) target name in full
#               --lead      (M) Leads name in full
#               --sr        (M) SR number
#               --cd        (M) Expected Date for Completion.
use strict;
use Thread;

use Win32::OLE;
use Win32::OLE qw(in with);
use Win32::GUI;
use Win32::GuiTest;
use IO::File;
use Getopt::Long;
use File::Basename;
use POSIX qw(tmpnam);


my $progname = basename($0);

## These variable will be used to store the command line argufromnts
my $email;      #= '';   # (M) target email address in full
my $to;         #= '';   # (M) target name in full
my $lead;       #= '';   # (M) Leads name in full
my $sr;         #= '';   # (M) SR number
my $cd;         #= '';   # (M) usernafrom to log into unix box

my $true    = 1;
my $false   = 0;


GetOptions ("email=s"       => \$email,
            "to=s"          => \$to,
            "lead=s"        => \$lead,
            "sr=s"          => \$sr,
            "cd=s"          => \$cd);

sub usage
{
    print("\nUsage:");
    print("\n\tperl domail.pl <options>");
    print("\n");
    print("\n\t<options>:   (M) = Mandetory; (O) = Optional");
    print("\n");
    print("\n\t--email      (M) target email address in full");
    print("\n\t--to         (M) target name in full");
    print("\n\t--lead       (M) Leads name in full");
    print("\n\t--sr         (M) SR number");
    print("\n\t--cd         (M) Expected Completion Date.");
    print("\n");
    print("\n\texample:");
    print("\n\tperl $progname -email \"receiver\@mycompany.com\" -to \"Mr Receiver\" -lead \"Mr Lead\" -sr SR0000000 -cd \"Friday 13 May 2005\"");
    print("\n");
    print("\n");
}

sub chkOpts
{
    my $status = 1;
    unless (defined $email)     {print ("\nRecepient email is not defined"); $status = 0;}
    unless (defined $to)        {print ("\nRecipient name is not defined"); $status = 0;}
    unless (defined $lead)      {print ("\nLeads name is not defined"); $status = 0;}
    unless (defined $sr)        {print ("\nSR in question is not defined");  $status = 0;}
    unless (defined $cd)        {print ("\nExpected Completion Date is not defined"); $status = 0;}

    if (!$status) {usage(); exit;}

}



my $thr1 = Thread->new(\&handleOutlookSecurity);

sub findSecurityWindow
# this method detects whether a security window popped up in Outlook. If it is
# the case, it needs to be processed so that the script can be executed.
# Else it'll pend.
{
   my $messageClass = "#32770";
   my $winName = "Microsoft Outlook";
   return Win32::GUI::FindWindow($messageClass,$winName);
}

sub clearSecurityWindow
# this method brings the security window on top of all the others, hence focusing it
# and sends it a series of keystrokes in order to validate it.
{
   my $securityHandle = shift;

   while ($securityHandle!=Win32::GUI::GetForegroundWindow())
   {
      Win32::GUI::SetForegroundWindow($securityHandle);
      Win32::GUI::Enable($securityHandle);
   }

   # now send key sequence that will allow maximum time for code to run
   # The sequence is as follows : initially the no button is focused...
   # One tab brings us to cancel, another tab to the time tick box
   # a spacebar hit will tick the box. Then a tab will select the drop-down
   # list in order for us to choose the time length. One more tab brings us to Yes. A keypress on the End key will
   # select maximum time. Then a return key will validate our choice
   # 2 tabs - spacebar - 2 tab - one end - one return

   Win32::GuiTest::SendKeys("{TAB}");
   Win32::GuiTest::SendKeys("{TAB}");
   Win32::GuiTest::SendKeys("{SPACEBAR}");
   Win32::GuiTest::SendKeys("{TAB}");
   Win32::GuiTest::SendKeys("{TAB}");
   Win32::GuiTest::SendKeys("{END}");
   Win32::GuiTest::SendKeys("{ENTER}");
}

sub clearSecurityWindow2
# this method does the same as clearSecurityWindow but handles the second security window.
{
   my $securityHandle = shift;

   while ($securityHandle!=Win32::GUI::GetForegroundWindow())
   {
      Win32::GUI::SetForegroundWindow($securityHandle);
      Win32::GUI::Enable($securityHandle);
   }
   Win32::GuiTest::SendKeys("{TAB}");
   Win32::GuiTest::SendKeys("{TAB}");
   Win32::GuiTest::SendKeys("{ENTER}");
}


sub handleOutlookSecurity
{
    # We don't need to sleep but just to be safe
    sleep 3;
    my $securityHandle = 0;

    while (not ($securityHandle)) # detects Outlook's popup window that asks whether access should be granted to
    {
       $securityHandle = findSecurityWindow(); # wait for security window to pop-up...
    }

    # window has been found - clear it
    clearSecurityWindow($securityHandle);

    # We need the "Yes" button to be active
    sleep 10;

    $securityHandle = 0;

    while (not ($securityHandle))
    {
       $securityHandle = findSecurityWindow(); # wait for security window to pop-up...
    }

    # window has been found - clear it
    clearSecurityWindow2($securityHandle);
}

sub main
{

    # init OLE, COINIT_OLEINITIALIZE required when using MAPI.Session objects
    Win32::OLE->Initialize(Win32::OLE::COINIT_OLEINITIALIZE);
    die Win32::OLE->LastError(),"\n" if Win32::OLE->LastError( );

    # Create a new MAPI session
    my $session = Win32::OLE->new('MAPI.Session')  or die "Failed to create a new MAPI Session!";

    # Logon to server
    my $res = $session->Logon('MS Exchange Settings','password','False');
    die "Could not log on to exchange server!" if ($res);

    # Create a new message
    my $msg = $session->Outbox->Messages->Add();

    # Add the recipient and resolve the address
    my $recipient = $msg->Recipients->Add();
    $recipient->{Name} = $email;
    $recipient->Resolve();

    # Add your text
    $msg->{Subject} = "DCA for SR $sr";
    $msg->{Text} = qq/
   Hello $to.

   As the Assessor\/Technical Authority for the SR $sr, you are required to participate in its Defect Case Analysis.
   Please complete in the appropriate Perspective section(s) of the DCA tool to the best of your knowledge and ability.


   The due date for completion of this task is $cd.

   Please work with your Lead for this SR, $lead, and be prepared to answer relating questions if called by the Defect Council.

   Thanks you for your cooperation.





   Regards
   The Council

   Please note that this is an auto generated email. Contact your Lead with any questions.
                 /;

    # Send the email
    # 1st argument = save copy of message
    # 2nd argument = allows user to change message w/dialog box before sent
    # 3rd argument = parent window of dialog if 2nd argument is True
    $msg->Update();
    $msg->Send(1, 0, 0);

    # Log off
    $session->Logoff();

}

chkOpts();
main();
 
FWIW, IMO it was great while it lasted. M$ may have closed a vulnerability that your code exploited, or they may have changed how they do things altogether.

When sending mail, personally, I don't like to rely on the mail client, and prefer instead to deal directly with the SMTP server. Have a look at Net::SMTP

It's an awful lot easier than the dependency tree you've got there, and there's more modules if your requirements become more advanced.

Just my €0.02
--Paul


cigless ...
 
The latest service pack for Exchange screwed with outside SMTP connections, so that may not be an option. We had to tell our database server to go somewhere else to send mail, I'm guessing perl would have similar issues. But agreed, that looks incredibly complicated for just sending mail, compared to what's required for something like Net::SMTP.

I don't mean to state the obvious, but the error says "Invalid class string". What is your class string and are you sure it's valid? What is a valid format/value for a class string?

________________________________________
Andrew

I work for a gift card company!
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top