Asynchronous Categorizer::ExpandItem Replace Content Problems

Asynchronous Categorizer::ExpandItem Replace Content Problems

Post by Aaron Well » Thu, 08 May 2003 07:17:01



In my Categorizer::ExpandItem event, I had been *mostly* successful at
replacing the content of the message using the IMailMsg.WriteContent method.
I say mostly successful because every once in awhile identical messages (I'm
using reply-all for each message) would not actually 'take' the new content;
the original content would be sent instead of the new.

I thought that I might be seeing some multi-threading issues where my object
was cached, but called from multiple threads, so I set
IEventIsCacheable.IsCacheable to S_FALSE. This made no difference.

So, I thought that there might be a timeout issue happening every so often.
I have placed all the working code in a thread and can see that it is
getting called properly and that I am calling back through the
IMailTransportNotify interface with no error result codes.

Here is the problem, even though I am getting affirmative responses from all
my bifurcation code (that worked most of the time before), it now never
bifurcates the message with the new content. In fact, it doesn't even seem
to allow me to bifurcate at all, just ignoring the calls that I am making.
i.e. the untouched message is always sent through.

Any ideas:
a) what could be causing some messages to have their content ignored when I
am not multi-threading?

b) why I can't change P1 recipients or the body in a separate thread?

thanks in advance.

-Aaron D. Wells

 
 
 

Asynchronous Categorizer::ExpandItem Replace Content Problems

Post by Daniel Longley [MSFT » Thu, 08 May 2003 11:27:42


Thread affinity shouldn't be an issue here. While your sink might be called
into on multiple threads at the same time, there will only be one thread
calling your sink per categorization at any given time. You don't have to
worry about any synchronization provided you're not sharing any state
between categorizations. If you're completing ExpandItem asynchronously, the
categorization owning that ExpandItem event is "blocked" while you're doing
your async processing. No other threads will do any work related to that
categorization until you post your ExpandItem completion through
IMailTransportNotify.

There's probably something else going on here...

Are you running this on a server with Exchange 2000 installed?

Bear in mind that the SMTP Server Events API is not an API designed for
extending Exchange 2000 -- it's an API for extending the Windows SMTP
Service. You're writing to the same API that the Exchange 2000 Transport
uses to implement its features. Your sink might be conflicting with the
Exchange 2000 Categorizer sink, which is also trying to bifurcate and move
recipients around.

What is your basis for concluding that the message is not being bifurcated?
If GetMailMsg is returning S_OK with TRUE in the pfCreated out parameter,
bifurcation is occurring. If you really want to verify what bifurcated
copies categorizer is holding, create a postcat sink to log the output from
categorizer. Every bifurcated copy will go through the postcat event.

It is entirely possible that you're successfully creating a bifurcated copy
of the original message and that all of your changes are being made intact,
but if the message leaves categorization with zero recipients on it then it
will be deleted without being delivered to anyone.

Specifically, if your sink is bound at a higher priority than the Exchange
2000 Categorizer (i.e. priority of your sink is less than 8192), then
depending on how you're submitting mail and who you're submitting it to, the
Exchange 2000 Categorizer might be doing its own bifurcation, removing the
recipients from your copy, and putting them onto its own message.

How are you submitting mail to your test server? What sort of recipients are
you sending to? (local? remote? contact? encoding settings? DLs?)

What steps are you taking after bifurcation + rebind to ensure that the
bifurcated copy is addressed to a set of P1 recipients?

Do you have any postcat logging to see what is actually coming out of
categorization?

--
Daniel Longley
Exchange Transport Developer
Microsoft Corporation

****** Disclaimer ******
This posting is provided "AS IS" with no warranties, and confers no rights.

Note: Please do NOT reply to this e-mail address. It is used for newsgroup
purposes only.


Quote:> In my Categorizer::ExpandItem event, I had been *mostly* successful at
> replacing the content of the message using the IMailMsg.WriteContent
method.
> I say mostly successful because every once in awhile identical messages
(I'm
> using reply-all for each message) would not actually 'take' the new
content;
> the original content would be sent instead of the new.

> I thought that I might be seeing some multi-threading issues where my
object
> was cached, but called from multiple threads, so I set
> IEventIsCacheable.IsCacheable to S_FALSE. This made no difference.

> So, I thought that there might be a timeout issue happening every so
often.
> I have placed all the working code in a thread and can see that it is
> getting called properly and that I am calling back through the
> IMailTransportNotify interface with no error result codes.

> Here is the problem, even though I am getting affirmative responses from
all
> my bifurcation code (that worked most of the time before), it now never
> bifurcates the message with the new content. In fact, it doesn't even seem
> to allow me to bifurcate at all, just ignoring the calls that I am making.
> i.e. the untouched message is always sent through.

> Any ideas:
> a) what could be causing some messages to have their content ignored when
I
> am not multi-threading?

> b) why I can't change P1 recipients or the body in a separate thread?

> thanks in advance.

> -Aaron D. Wells


 
 
 

Asynchronous Categorizer::ExpandItem Replace Content Problems

Post by Aaron Well » Fri, 09 May 2003 06:57:20


Thanks again for your response Daniel.

My test machine is configured thusly:

I have Exchange 2000 and a PDC/GC installed on Windows 2000 sp3. I have a
second SMTP virtual server running as well, it is configured as a
"bridgehead" in that the outgoing SMTP traffic from the first SMTP server is
routed to the second via port 26 as described in kb 28756. I did this so
that I wouldn't need to deal with the TNEF message format. My Categorizer is
registered to run on the second SMTP virtual server as described in the same
kb article.I have not adjusted the priority of my categorizer sink from the
default. Here is the entry from the smtpreg.vbs script:

               --------
              | Source |
               --------
               Name: smtpsvc 2
                 ID: {1B3C0666-E470-11D3-AA67-80C04FA345F6}

                        ---------
                       | Binding |
                        ---------
                                   Event: SMTP OnCategorize
                                      ID:
{6591D716-AB8F-489D-9F96-B2672F6FC3DB}
                                    Name: CategorizeMultipleTo
                               SinkClass: MultipleTo.MultipleTo
                                 Enabled: True
                        SourceProperties: {
                                           Priority = 24575
                                          }

My test environment for the messages consists of using OWA and Outlook
Express to originate messages within exchange. In practice, I keep one
message in the inbox and simply do a "reply all" and "send" on the message.
This gives me identical message content every time that I run the test. My
test case consists of two external recipients, and one internal recipient.
My code should take one original message and create two bifurcations, one
for each external recipient containing a changed To: line. The to: line
should contain only the internal recipients and the one external recipient
(hiding the identity of the other external recipients)

What I am experiencing in my test is that "identical" messages that are sent
through the sink are processed the same (as confirmed by a log file that I
create during each message execution, and text file dumps of the content
that I've created), but that when they leave the sink, occasionally, either
a) the content of the bifurcation is disregarded, but the bifurcation and
its new P1 recipients are honored, or b) the bifurcation is not honored and
the original message (with all its P1 recipients) is sent forward.

I will write a logging agent in PostCategorization to see which of these is
happening for sure.

This occurs only once or twice when the sink is run synchronously, but every
time if I do this asynchronously.

As far as what the code is doing after I rebind the bifurcated message,

After I determine that this is a message that needs split, I do the
following:

put the original message content into a memory stream.
make a copy of the body of the message in a separate stream
Load the header of the message into an email message parser and read the P2
To: recipients.

I loop through each recipient and divide them into external and internal
groups

for each of the P2 recipients that are external to the organization I...
Copy the message header information,
Replace all the To: recipients of the P2 header with the internal addressed
recipients
Add the one external P2 recipient to the header
put the new header and original body into a new stream
replace the body of the bifurcated message with the newly constructed one.
Add the external recipient as the only P1 recipient

After creating the bifurcated messages, I
Find and remove the external recipients from the original message
Replace the recipients list on the original message with the new list
(without external recipients)

Along the way I optionally log some information to various files

Here is some code:

-=-=-=-=-=-=

if ICATEGORIZERITEM_SOURCETYPE = SOURCE_SENDER then

begin
  // Get the ICategorizerMailMsgs

OleCheck(pICatItem.GetICategorizerMailMsgs(ICATEGORIZERITEM_ICATEGORIZERMAIL
MSGS, pICatMailMsgs));

  // Get the original message from the mail messages list
  OleCheck(pICatMailMsgs.GetMailMsg(0, ppIMailMsg, ppIMailMsgRecipientsAdd,
pfCreated ));

    //  Process messages from multiple to: clients only
    if not
MultipleToClient( mmOriginal.GetProperty( IMMPID_MP_SENDER_ADDRESS_X500 ) )
      then exit;

    case LogLevel[1] of
      '1':
        begin
          LogEvent( 'Message ID: %s',
[mmOriginal.GetProperty(IMMPID_MP_RFC822_MSG_ID)]);
          LogEvent( 'Sender: %s', [mmOriginal.GetSenderSMTP]);
        end;
      '2': mmOriginal.ListProperties;
    end;

    // Create the SMTP message wrapper
    P2:= TIDMessage.Create(nil);
    // Create the internal and external To: list
    ealInternal:= TIdEmailAddressList.Create(nil);
    ealExternal:= TIdEmailAddressList.Create(nil);
    // Create the utility Memory streams
    stmOriginal:= TMemoryStream.Create;
    stmBody:= TMemoryStream.Create;

    try
      mmOriginal.GetContent(stmOriginal);
      SplitMessage(stmOriginal, nil, stmBody);

      // Output the file
      if LogLevel > '1' then
        stmOriginal.SaveToFile(Format('%sOriginalMsg.log',[DllPath]));

      // Load it into Indy for manipulation
      stmOriginal.Position:= 0;
      P2.LoadFromStream(stmOriginal, True);

      // Find the internal and external recipients
      for idx:= 0 to P2.Recipients.Count - 1 do
        begin
          tmpEAItem:= P2.Recipients.Items[idx];
      //  determine if the address is internal or external based on
      //  the ini file masks
          if IsInternalAddress( tmpEAItem ) then
            ealInternal.Add.Assign(tmpEAItem)
          else
            ealExternal.Add.Assign(tmpEAItem);
        end;

      LogEvent('-=- internal addresses -=-');
      LogEvent(ealInternal.EMailAddresses);
      LogEvent('-=- external addresses -=-');
      LogEvent(ealExternal.EMailAddresses);

      // create a new email message for each external address
      for idx:= 0 to ealExternal.Count - 1 do
        begin
          tmpEAItem:= ealExternal.Items[idx];
        // Bifurcate the message for each external recipient
          OleCheck(pICatMailMsgs.GetMailMsg(idx+BaseMsgID, ppIMailMsgNew,
ppIMailMsgRecipientsAdd, pfCreated ));

        // Pre-bifurcated message, nothing to do
          if pfCreated <> 1 then exit;

          LogEvent(#9'Bifurcating (%d) for: %s',[idx+BaseMsgID,
tmpEAItem.Text]);
        // add the recipient to the bifurcated P1 envelope
          AddSMTPRecipient(ppIMailMsgRecipientsAdd, tmpEAItem.Address);

        // Must rebind to access the message body on the bifurcation
          OleCheck(pICatMailMsgs.ReBindMailMsg(idx+BaseMsgID, nil));

        // replace the P2 envelope with a new one
          mmNew:= TMailMsg.Create(ppIMailMsgNew);
        // create a new target stream
          stmNew:= TMemoryStream.Create;
          try
            // Copy all the internal addresses
            P2.Recipients.Assign(ealInternal);
            // Append the one external address
            P2.Recipients.Add.Assign(tmpEAItem);
            stmNew.Size:= 0;
            P2.SaveToStream(stmNew, True);
            stmBody.Position:= 0;
            stmNew.CopyFrom(stmBody, stmBody.size);

            // Write out the new message to the bifurcation
            mmNew.SetContent(stmNew);

            if LogLevel > '1' then

stmNew.SaveToFile(format('%sNewMessage-%d.log',[DllPath,idx+BaseMsgID]));
            if LogLevel > '1' then
              logEvent(#9'%sNewMessage-%d.log
written',[DllPath,idx+BaseMsgID]);

          finally
            // Clean up the memory stream
            stmNew.Free;
            // Clean up the new message
            mmNew.Free;
          end;

          // remove the bifurcated recipient from the original message
          for idy:= mmOriginal.Recipients.Count - 1 downto 0 do
            begin
              tmpRecipient:= mmOriginal.Recipients.Item[idy];
              if (tmpRecipient.AddrType = atSMTP) and
                  (AnsiCompareText( tmpRecipient.Address,
tmpEAItem.Address )=0) then
                begin
                  mmOriginal.Recipients.Remove(idy);
                  logEvent(#9'removed %s from original
message.',[tmpEAItem.Address]);
                end;
            end;
        end;
      mmOriginal.Recipients.Commit;
    finally
      mmOriginal.Free;
      ealInternal.Free;
      ealExternal.Free;
      stmOriginal.Free;
      stmBody.Free;
    end;
  except
    on e:Exception do
      begin
        LogEvent( e );
      end;
end;

"Daniel Longley [MSFT]" <dlong...@online.microsoft.com> wrote in message
news:euit9AEFDHA.2288@TK2MSFTNGP12.phx.gbl...

> Thread affinity shouldn't be an issue here. While your sink might be
called
> into on multiple threads at the same time, there will only be one thread
> calling your sink per categorization at any given time. You don't have to
> worry about any synchronization provided you're not sharing any state
> between categorizations. If you're completing ExpandItem asynchronously,
the
> categorization owning that ExpandItem event is "blocked" while you're
doing
> your async processing. No other threads will do any work related to that
> categorization until you post your ExpandItem completion through
> IMailTransportNotify.

> There's probably something else going on here...

> Are you running this on a server with Exchange 2000 installed?

> Bear in mind that the SMTP Server Events API is not an API designed for
> extending Exchange 2000 -- it's an API for extending the Windows SMTP
> Service. You're writing to the same API that the Exchange 2000 Transport
> uses to implement its features. Your sink might be conflicting with the
> Exchange 2000 Categorizer sink, which is also trying to bifurcate and move
> recipients around.

> What is your basis for concluding that the message is not being
bifurcated?
> If GetMailMsg

...

read more »

 
 
 

1. Message Categorizer problem

We are running Small Business Server 2000 with Exchange
2000 SP3.

We encountered a problem recently where a mail that should
have been routed via Exchage (i.e. and internal address)
got send out through the SMTP connector.  The SMTP server
rejected the message.

As far as I understand things the Message Categorizer
should have routed the message through to the relevant
mailbox in the information store and not through to the
SMTP server.

Any help would be much appreciated.

2. Attachments Questions

3. HELP !! MSExchangeIS ((224) ) Asynchronous read page time error

4. Sharing calendar

5. HELP!!!!MSExchangeIS ((224) ) Asynchronous read page time error

6. Note field in AddressBook/Exchange

7. Exchange 2000 Asynchronous Event handling

8. Backing up Folders on M: drive

9. Asynchronous event not firing

10. Is IBodyPart.SaveToFile Asynchronous?

11. Asynchronous binding is not supported

12. Replacing an Exchange server and getting SQL problems

13. replace exchange server - public folders problem