Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Simple MAPI hangs

195 views
Skip to first unread message

Jonathan Olson

unread,
Dec 13, 1999, 3:00:00 AM12/13/99
to
I am using Simple MAPI to send email in a file distribution application.
It's a relatively simple piece of software that consists of two threads
(client/GUI thread and the processing thread). The processing thread loads
the MAPI dll when it is first needed, gettting the MAPILogon, MAPISendMail,
and MAPILogoff addresses as well. MAPILogon is called to get a session id.
MAPISendMail is called to actually send the email. And MAPILogoff is called
to terminate the session. The dll stays loaded until shutdown, in case
another email will be sent. Simple, right?

What seems to be happening is that sometimes the MAPISendMail call never
returns. This usually seems to happen when the program is run, some emails
are sent, the program exits, the program restarts, and some more emails are
sent. What has been noticed is that MAPISP32.EXE remains running between
executions. When the system gets into the state where MAPISendMail hangs, I
have to EndProcess MAPISP32.EXE to get anything mail related to work.

I am running NT 4.0 (sp 3, I think...). Sample code follows....

Jonathan S. Olson
jol...@pcinnovators.com

bool CMapiSupport::bInitializeMapi(void)
{
if ( m_hMapi == NULL )
{
// Load the simple MAPI library.
m_hMapi = LoadLibrary(_T("MAPI32.DLL"));
if ( m_hMapi != NULL )
{
m_lpLogon = (LPMAPILOGON)GetProcAddress(m_hMapi,
_T("MAPILogon"));
m_lpLogoff = (LPMAPILOGOFF)GetProcAddress(m_hMapi,
_T("MAPILogoff"));
m_lpSendMail = (LPMAPISENDMAIL)GetProcAddress(m_hMapi,
_T("MAPISendMail"));
}

if ( (m_lpLogon == NULL) || (m_lpLogoff == NULL) || (m_lpSendMail ==
NULL) )
{
vShutdownMapi();
}
}

return ( m_hMapi != NULL );
}

...

m_hMapiSession = NULL;
if ( (bInitializeMapi()) && (m_lpLogon != NULL) )
{
// Get the MAPI function pointers.
ULONG ulStatus = (*m_lpLogon)(0, bstrProfileName, bstrPassword,
MAPI_NEW_SESSION, 0, &m_hMapiSession);
if ( ulStatus != SUCCESS_SUCCESS )
{
vLogMapiError(pcDestination, ulStatus);
return false;
}
else
{
// Setup the email message
...

ulStatus = (*m_lpSendMail)(m_hMapiSession, 0, &m_structMessage,
0, 0);
}
}

...

void CMapiSupport::vShutdownMapi(void)
{
if ( m_hMapi != NULL )
{
::FreeLibrary(m_hMapi);
m_hMapi = NULL;
}

m_lpLogon = NULL;
m_lpLogoff = NULL;
m_lpSendMail = NULL;
}

Jonathan Olson

unread,
Dec 13, 1999, 3:00:00 AM12/13/99
to
Another data point....

It appears that the problem is related to the fact that my program is doing
the following:

MAPILogon
MAPISendMail
MAPILogoff

< Repeat a bunch of times >

It appears that MAPISendMail just queues the message up for delivery, but
doesn't actually deliver the message. After the last MAPILogoff, whatever
messages didn't get actually delivered stay in the queue until some other
MAPI client runs that can deliver them. BUT, MAPISP32.EXE needs to be
killed first, or that MAPI client (Outlook 97 in my case) won't be able to
do any sending or receiving.

I have tested this a number of time in a number of variations, and it seems
that, as long as my program does not call MAPILogoff, all of the messages
will get delivered. So, is there some way to determine if all of the email
has actually been sent? Or am I doing something else wrong?

Thanks!

Jonathan S. Olson
jol...@pcinnovators.com

Jonathan Olson wrote in message ...


>I am using Simple MAPI to send email in a file distribution application.
>It's a relatively simple piece of software that consists of two threads
>(client/GUI thread and the processing thread). The processing thread loads
>the MAPI dll when it is first needed, gettting the MAPILogon, MAPISendMail,
>and MAPILogoff addresses as well. MAPILogon is called to get a session id.
>MAPISendMail is called to actually send the email. And MAPILogoff is
called
>to terminate the session. The dll stays loaded until shutdown, in case
>another email will be sent. Simple, right?
>
>What seems to be happening is that sometimes the MAPISendMail call never
>returns. This usually seems to happen when the program is run, some emails
>are sent, the program exits, the program restarts, and some more emails are
>sent. What has been noticed is that MAPISP32.EXE remains running between
>executions. When the system gets into the state where MAPISendMail hangs,
I
>have to EndProcess MAPISP32.EXE to get anything mail related to work.
>
>I am running NT 4.0 (sp 3, I think...). Sample code follows....
>

< snip >


Eric June

unread,
Dec 14, 1999, 3:00:00 AM12/14/99
to
Simple MAPI will return a success code if your message gets successfully
queued in the Outbox. You will have no way of telling
(programmatically) if the messages actually get sent out successfully.
Note that you can force the mail system to flush your outbox by logging
out and calling MAPILogon with the MAPI_FORCE_DOWNLOAD flag set.

There are many articles on MSDN regarding problems with the MAPI
spooler. Here is one:

http://support.microsoft.com/support/kb/articles/q179/4/62.asp?FR=0

Personally, I would use SMTP for what you are doing. It is typically
much more reliable.

--
- Eric June ej...@intuitive-data.com

Jacob de Bruin

unread,
Dec 15, 1999, 3:00:00 AM12/15/99
to
Hi Jonathan,

Some additional info on Eric June's reply.

MAPILogon() with MAPI_FORCE_DOWNLOAD flag set does not always force all
messages to be delivered. Depends on how fast your app finishes after the
last send and how fast the MAPISP32 gets the external connection, etc.
MAPILogoff() usually does not return until all messages are delivered if
MAPI_FORCE_DOWNLOAD flag is set with MAPILogon, but I've seen impatient
Win32/Console apps that finish before even the external connection was
established.

You may gain some control over the actual sending of outbound mail by the
FlushQueues() method of Extended MAPI.
By the ScMAPIXFromSMAPI function you can get back a pointer to a MAPI
session object from the Simple MAPI session handle.
From there you can follow the MSDN MAPI SDK sample ROUTE.CLI.
(See function DeliverNow() in source file "Client.c": just as a skeleton;
you'd better cleanup the dirty load-of-goto's-and-Asserts() in MS sample
stuff like this).

On the other hand: is it possible to change the loop:
- while (!Ready) { Logon(); Send(); Logoff() }
into something like:
- Logon(); while (!Ready) { Send(); } Logoff()

As for using SMTP: (if I get Eric right: without using the Personal Folders
bit).
If you use Simple MAPI or CMC with mail clients like Exchange or Outlook you
benefit of the built-in recovery mechanism of the mail client itself.
Unsent messages stay queued until sent once submitted through MAPI/CMC.
Still I only wish (Extended) MAPI would provide for some method to get the
status of the outbound queue.
There is some circumstantial evidence using flags from status table.
But that is tricky stuff I guess.
Anybody have any suggestions/articles on:
***
HOW TO GET STATUS INFO ABOUT UNSENT MESSAGES.
(please)
***

Jacob de Bruin.

Eric June heeft geschreven in bericht
<0999111414114...@intuitive-data.com>...

Jonathan Olson

unread,
Dec 16, 1999, 3:00:00 AM12/16/99
to
I have modified to code to delay the Logoff until either the program exits
or a different profile is specified for an email. This improves the
performance of the application (Logon apparently takes quite a bit of
time/cycles), but it also makes it more likely to hang the MAPI spooler.
The user now sees that the emails have been sent MUCH quicker and probably
thinks that they can exit the program sooner, which will force the Logoff.
Unfortunately, this results in messages being left in the Outbox, causing
the problems described before.

You said that if FORCE_DOWNLOAD is set during Logon that the spooler will
wait for the Outbox to clear before exiting. The only place that I found
that even mentioned what the spooler does when it exits was an obscure KB
article. It said that, after a connection closes the spooler will exit,
clearing the Outbox first. That's the behavior I'd like, but it appears to
hang instead. I haven't tried using the FORCE_DOWNLOAD, as I'd rather not
have the Logon actually download the messages (this program should be send
only).

As to using Extended MAPI, I was hoping to avoid that. Can't even seem to
find the proper headers and libraries for it.... And having the program
wait while the spooler does its job is a bit annoying. Why can't it
properly send the messages asynchronously in its separate process space
after I Logoff????

Thanks for the response!

Jonathan S. Olson
jol...@pcinnovators.com

Jacob de Bruin wrote in message <838e0e$7d9$1...@news1.xs4all.nl>...

Eric June

unread,
Dec 21, 1999, 3:00:00 AM12/21/99
to
Jonathan,

You might want to consider using SMTP (internet mail) and avoiding MAPI
altogether since you are encountering instability problems with the MAPI
spooler. You can use our IDSMail component with code like this:

Dim idsMail as Object
Set idsMail = CreateObject("IDSMailInterface32.Server")
idsMail.ObjectKey = "ABC123"
idsMail.MailSystem =IDSM_SYS_SMTP_POP
idsMail.SMTPServer = "myprovider.com"
idsMail.NewMessage
idsMail.From = "MyName <m...@mycompany.com>"
idsMail.AddRecipientTo "Jim Smith <jsm...@example.com>"
idsMail.AddRecipientCc "Mary Brown <ma...@example.gov>"
idsMail.Subject = "Meeting Agenda"
idsMail.Message = "Here is the agenda for the weekly meeting."
idsMail.AddAttachment "C:\MEETINGS\AGENDA.DOC"
idsMail.Send

The message will be sent to the SMTP server immediately. If you need to
establish a dial-up connection first, you can use the IDSMail Dialer
object. IDSMail also interfaces to any mail systems based on MAPI,
SMTP/POP3 (Internet mail), VIM (Lotus), MHS (Novell), CDO, Active
Messaging, Lotus Notes API, and Banyan VINES. For more info, go to
http://www.intuitive-data.com

0 new messages