Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Sample 10.3 POP3 code moving from Indy 9 on D7
#1
Converted our D7 & Indy 9 application to Studio 10.3 & Indy 10 with one exception:   POP3 email processing.  Under Indy 9, our code worked as we wished.  Moving to Indy 10 apparently requires an additional module which we have yet to identify.

The following identifiers become 'undeclared idenitifier":

 [            if (EmailMsg.MessageParts.Items[Jdx] is TIdAttachment) then


              if EmailMsg.MessageParts.Items[Jdx] is TIdText then

              pnlAttachments.visible := true;
              li := lvMessageParts.Items.Add;
              li.ImageIndex := 8;
              li.Caption := TIdAttachment(Msg.MessageParts.Items[Jdx]).Filename;
              li.SubItems.Add(TIdAttachment(Msg.MessageParts.Items[Jdx]).ContentType);
]

We greatly appreciate the Indy Project it has been a great assistance to us since the release of Indy9.

Jack
Reply
#2
Which identifiers is the compiler complaining about exactly?  Please be more specific. Is it complaining about TIdAttachment and TIdText, by chance? If so, you need to add the IdAttachment and IdText units to your uses clause. In Indy 9, everything was in the IdMessage unit. In Indy 10, things like TIdMessageParts, TIdText, TIdAttachment, etc have been broken out into their own units.

Also, your code is a little confusing, as an item in the TIdMessage.MessageParts collection can't be both a TIdAttachment and a TIdText at the same time, and type-casting a TIdText to a TIdAttachment is wrong.  I think you are missing some begin..end blocks in this code, or maybe the TIdText check doesn't belong at all.

Reply
#3
When I add TIdMessageParts, TIdText, and TIdAttachment to the uses clause, Delphi 10.3 flags them as unknown identifiers. 

Sorry, I did not include all the code..... just the parts Delphi 10.3 complained about.  Here is the actual code:

Code:
EmailCount := Pop3.CheckMessages;  // How many emails are waiting
for Idx:= 1 to EmailCount do
begin
  for Jdx := 1 to 50 do
    App_Products[Jdx] := '';
  EmailMsg.Clear;
  Pop3.Retrieve(Idx,EmailMsg);
  Subject := EmailMsg.Subject;
  if (Pos('New Shop Order from App!', Subject) = 0) or (Subject = '') then
    continue;
  Header := EmailMsg.Headers.Text;
  Jdx := Pos('Message-ID', Header);
  Order_ID := Copy(Header, Jdx + 13, 100);
  Jdx := Pos('@', Order_ID);

  SetLength(Order_ID, Jdx - 1);
  if not New_Order then
    continue;
  From := EmailMsg.From.Address;
  FromText := EmailMsg.From.Text;
  ToWhom := EmailMsg.Recipients.EMailAddresses;
  if ToWhom = '' then continue;
  Date_Str := FormatDateTime('dd mmm yyyy hh:mm:ss', EmailMsg.Date);
  App_entry := 0;
  App_Receipt := Get_Next_Seq('APPORDER');
  for Jdx := 0 to Pred(EmailMsg.MessageParts.Count) do
  begin
    if (EmailMsg.MessageParts.Items[Jdx] is TIdAttachment) then
    begin //general attachment
      pnlAttachments.visible := true;
      li := lvMessageParts.Items.Add;
      li.ImageIndex := 8;
      li.Caption := TIdAttachment(Msg.MessageParts.Items[Jdx]).Filename;
      li.SubItems.Add(TIdAttachment(Msg.MessageParts.Items[Jdx]).ContentType);
    end
    else
    begin //body text
      if EmailMsg.MessageParts.Items[Jdx] is TIdText then
      begin
        Parse[Jdx] := EMailMsg.TIdText(EmailMsg.MessageParts.Items[Jdx]).Body;
        if Jdx = 1 then
        begin
          Parse_Order;
          Body := Parse[Jdx].Text;
        end;
      end;
    end;
  end;
Reply
#4
(02-28-2019, 04:40 PM)jackmason@mindspring.com Wrote: When I add TIdMessageParts, TIdText, and TIdAttachment to the uses clause, Delphi 10.3 flags them as unknown identifiers. 

Please re-read my previous reply again more carefully.  I did not say to add TIdMessageParts, TIdText, and TIdAttachment to the uses clause, I said to add IdMessageParts, IdText, and IdAttachment instead.  Indy's unit names do not begin with T, class types do.  There is a difference between a unit name and a class name.  You should know this, as it is basic Delphi 101 kind of stuff.

(02-28-2019, 04:40 PM)jackmason@mindspring.com Wrote: Sorry, I did not include all the code..... just the parts Delphi 10.3 complained about.  Here is the actual code:

I see a few issues with that code.

(02-28-2019, 04:40 PM)jackmason@mindspring.com Wrote:
Code:
Header := EmailMsg.Headers.Text;
Jdx := Pos('Message-ID', Header);
Order_ID := Copy(Header, Jdx + 13, 100);

Use the TIdMessage.MsgId property instead of parsing the TIdMessage.Headers.Text manually:

Code:
Order_ID := EmailMsg.MsgId;

(02-28-2019, 04:40 PM)jackmason@mindspring.com Wrote:
Code:
for Jdx := 0 to Pred(EmailMsg.MessageParts.Count) do

Depending on the actual format of the email, technically the proper way to handle MIME-encoded emails is to process the parts in reverse order, as they are supposed to be ordered from least complex to most complex, and also take MIME nesting levels into account by looking at their ParentPart and ContentType properties.  Loop through the MessageParts from back to front handling only the items whose ParentPart is -1.  If you discover an item whose ContentType is "multipart/..." and you want to dig into its child parts, then loop through the MessageParts again from back to front looking for child items whose ParentPart is the parent item's Index.  And so on, recursively, as needed.

(02-28-2019, 04:40 PM)jackmason@mindspring.com Wrote:
Code:
if (EmailMsg.MessageParts.Items[Jdx] is TIdAttachment) then
begin //general attachment

For instance, you can also take the attachment's ParentPart property into account to ignore attachments that are not really meant for the user, for instance those that are embedded media used inside of HTML emails, eg:

Code:
if (EmailMsg.MessageParts.Items[Jdx] is TIdAttachment) then
begin //general attachment
 ParentIdx := EmailMsg.MessageParts.Items[Jdx].ParentPart;
 if ParentIdx <> -1 then
   ParentContentType := EmailMsg.MessageParts.Items[ParentIdx].ContentType
 else
   ParentContentType  := EmailMsg.ContentType;
 //if not IsHeaderMediaType(ParentContentType, 'multipart/mixed') then
 if IsHeaderMediaType(ParentContentType, 'multipart/related') then
     Continue;
 ...
end
else
...

(02-28-2019, 04:40 PM)jackmason@mindspring.com Wrote:
Code:
if EmailMsg.MessageParts.Items[Jdx] is TIdText then
begin
 Parse[Jdx] := EMailMsg.TIdText(EmailMsg.MessageParts.Items[Jdx]).Body;

EMailMsg.TIdText(...) is wrong syntax, EMailMsg.TIdText should be just TIdText by itself:

Code:
Parse[Jdx] := TIdText(EmailMsg.MessageParts.Items[Jdx]).Body;

Also, not all TIdText objects are text content meant for the user, either.  "multipart/..." items use TIdText, too.  You need to pay attention to the ContentType when looking for text to process, eg:

Code:
if EmailMsg.MessageParts.Items[Jdx] is TIdText then
begin
 if IsHeaderMediaType(EmailMsg.MessageParts.Items[Jdx].ContentType, 'text/plain') then
 begin
   Parse[Jdx] := TIdText(EmailMsg.MessageParts.Items[Jdx]).Body;
   ...
 end
 else if IsHeaderMediaType(EmailMsg.MessageParts.Items[Jdx].ContentType, 'text/html') then
 begin
   ...
 end;
end;

Reply
#5
Big Grin
Thank you very much.  I should have known that and been paying more attention to your first response.  However, in my defense, your subsequent responses provide valuable information I needed.

Thank you again, very much!!
Big Grin
Reply


Forum Jump:


Users browsing this thread: 1 Guest(s)