Search code examples
c++indy10

Problem with receiving mails from the SENT folder


if ( IdIMAP1->SelectMailBox( "SENT" ) )
{
   TIdIMAP4SearchRec sr[1]; 
   sr[0].SearchKey = skAll;
    
   IdIMAP1->UIDSearchMailBox( EXISTINGARRAY(sr) );
    
   int ile = IdIMAP1->MailBox->SearchResult.Length;
}

Error:

First chance exception at $757BF192. Exception class EIdReadLnMaxLineLengthExceeded with message 'Max line length exceeded.'.

It tries to read messages from the SENT folder and the program throws an error. There is no error when receiving from another SENT subfolder.

It seems to me that the problem lies in specifying SearchKey when the value is set to skAll, but no other setting reads the email despite the lack of an error. What does this error mean and how can I fix it?

By the way, I have a question about the SearchKey settings. Is it possible to give a specific date here that would filter emails only from today, for example?


Solution

  • Error:

    First chance exception at $757BF192. Exception class EIdReadLnMaxLineLengthExceeded with message 'Max line length exceeded.'.

    ... What does this error mean and how can I fix it?

    It means TIdIMAP4 called the IOHandler.ReadLn() method and received more than 16K worth of data that had no line breaks in it. The default value of the IOHandler.MaxLineLength property is 16384, and the default value of the IOHandler.MaxLineAction is maException.

    To workaround the error, you could try increasing the value of the MaxLineLength (say, to MaxInt). However, a proper fix would be to prevent such a large amount of undelimited data to be received in the first place.

    The response of UIDSearchMailBox() is a single line containing a list of email sequence numbers delimited by spaces, so you could be getting the EIdReadLnMaxLineLengthExceeded error here if the search is producing a LOT of sequence numbers (say, thousands of them, which makes sense when searching for just skAll on a large mailbox).

    You really should not be searching for just skAll by itself to begin with. If you want to access all emails in the mailbox, just iterate the mailbox instead. After SelectMailBox() returns success, TIdIMAP4.MailBox.TotalMsgs will contain the number of emails currently in the mailbox. You can then run a loop retrieving individual emails as needed using sequence numbers in the range of 1..TotalMsgs, inclusive.

    Otherwise, filter your search criteria better to produce fewer results.

    By the way, I have a question about the SearchKey settings. Is it possible to give a specific date here that would filter emails only from today, for example?

    Yes, of course. Look at the TIdIMAP4SearchKey enum, it lists all of the different keys you can search on, for instance:

    skOn,        //Messages whose internal date is within the specified date.
    skSentOn,    //Messages whose [RFC-822] Date: header is within the specified date.
    skSentSince, //Messages whose [RFC-822] Date: header is within or later than the specified date.
    skSince,     //Messages whose internal date is within or later than the specified date.
    

    In this case, either of those should work, depending on whether you want to search the email's internal server timestamps or their Date headers, eg:

    if ( IdIMAP1->SelectMailBox( "SENT" ) )
    {
       TIdIMAP4SearchRec sr[1]; 
       sr[0].SearchKey = skSince;
       sr[0].Date = Sysutils::Date(); // or Dateutils::Today()
        
       IdIMAP1->UIDSearchMailBox( EXISTINGARRAY(sr) );
        
       int ile = IdIMAP1->MailBox->SearchResult.Length;
    }
    

    UPDATE

    this example refer to expresion 'later than the specified date' but I can see that it is possible to use 'within'. How to set range of data? Is it possible in SearchKey settings?

    There is no 'within' search key in IMAP. If you are referring to RFC 5032: WITHIN Search Extension to the IMAP Protocol (the OLDER and YOUNGER search keys), then TIdIMAP4 does not implement this extension at this time. I have opened a ticket to add it in a future release:

    #420: Update TIdIMAP4 to support RFC 5032: "WITHIN Search Extension to the IMAP Protocol"

    In the meantime, you can combine multiple search keys and they will be logically AND'ed together, eg:

    if ( IdIMAP1->SelectMailBox( "SENT" ) )
    {
       TDateTime dtNow = Sysutils::Now();
    
       TIdIMAP4SearchRec sr[2]; 
       sr[0].SearchKey = skSince;
       sr[0].Date = Dateutils::StartOfTheDay(Dateutils::IncDay(dtNow, -6));
       sr[1].SearchKey = skBefore;
       sr[1].Date = dtNow;
        
       IdIMAP1->UIDSearchMailBox( EXISTINGARRAY(sr) );
        
       int ile = IdIMAP1->MailBox->SearchResult.Length;
    }
    

    I suggest you read RFC 3501 Section 6.4.4 for how the SEARCH command works and what the standard search keys are.