Archived Forum Post

Index of archived forum posts

Question:

Problems with IMAP

Sep 16 '16 at 07:46

I am using the latest and greatest version of Chilkat.Imap and I am receiving the following error:

08:48:12|Debug|Getting message set for: CL1654@dealercarsearchcrm.com
08:48:12|Debug|ChilkatLog:
  Search:
    DllDate: Jun 13 2016
    ChilkatVersion: 9.5.0.58
    UnlockPrefix: XXXXXXXXXXX
    Architecture: Little Endian; 64-bit
    Language: .NET 4.5 / x64
    VerboseLogging: 0
    Not in the selected state
  --Search
--ChilkatLog

08:48:12|Debug|Unexpected Error: System.NullReferenceException: Object reference not set to an instance of an object.
   at CLAPI_EmailService.EmailService.DoWork()

Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object.
   at CLAPI_EmailService.ExceptionErrorHandler.AddError(IErrorType ex)
   at CLAPI_EmailService.EmailService.DoWork()
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boo
lean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean pre
serveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ThreadHelper.ThreadStart()

I have been through my code and I can't find anything wrong. This is all being done in a console app on a 64 bit 2012 Windows server. Is it possible there is a bug in the Chilkat.IMAP software?


Accepted Answer

Problem in this line : imap.ExpungeAndClose();

It closes connection to server. After this you should login and select messagebox again.


Answer

The Imap.Search method returns a MessageSet object, or null if it failed. Your NullReferenceException is because Search returned null and then you tried to dereference the null. (Not a bug in Chilkat.)

"Not in a selected state" means no mailbox has yet to be selected. To search a mailbox, you must first select one. (It could also mean that at some point the connection to the IMAP server was lost. Make sure you check the return value of any IMAP method call that communicates with the server to know when things go bad...)


Answer

I only have 2 places in my code where MessageSet i used. Here is how I am handling them:

//First call
Chilkat.MessageSet oldMessages = imap.Search("SEEN", fetchUids);
if (oldMessages == null)
{
   LogMessage(LogLevel.Info, imap.LastErrorText, 0, 0, "");
   return;
}

//get the emails
Chilkat.EmailBundle oldBundle = imap.FetchBundle(oldMessages);

//second call
//  Get the set of unseen message UIDs
LogMessage(LogLevel.Debug, String.Format("Getting message set for: {0}", EmailAddressToCheck), 0, 0, "");
Chilkat.MessageSet messageSet = imap.Search("NOT SEEN", fetchUids);
if (messageSet == null)
{
   LogMessage(LogLevel.Info, imap.LastErrorText, 0, 0, "");
   return returnValue;
}

returnValue = imap.FetchBundle(messageSet);

So for both I try to get the message set and then check to see if it's null. If it's null I exit the method. Should I be doing some other check?


Answer

Any Chilkat method that returns an object (such as imap.FetchBundle returns a Chilkat.EmailBundle object), will return null on failure. You should check for a null return in any such case.

Also, FetchBundle is fine if the number of messages is not too large. However, if the number of messages is huge then FetchBundle is not the best choice for downloading email.


Answer

I believe I narrowed it down to one method. It seems that the error only happens when I am deleting mail from the server. I removed this method from the code and everything seems to work. It turns out my mail server has a way to expunge all messages older than "n" days automatically I so am going to use that to clear out old messages. Here is the entire delete method. I still don't see any obvious errors that would throw the null reference exception. Do you?

private void DeleteOldMessages(Chilkat.Imap imap)
{
    bool success = false;
    bool fetchUids = true;

    //number of days of email to be kept
    int KeepDays = Convert.ToInt32(ConfigurationManager.AppSettings["EmailKeepDays"]);

    //count the number of delete messages
    int deletedMessageCount = 0;

    LogMessage(LogLevel.Debug, "Checking for messages to delete", 0, 0, "");

    Chilkat.MessageSet oldMessages = imap.Search("SEEN", fetchUids);
    if (oldMessages == null)
    {
        LogMessage(LogLevel.Info, imap.LastErrorText, 0, 0, "");
        return;
    }

    //get the emails
    Chilkat.EmailBundle oldBundle = imap.FetchBundle(oldMessages);

    if (oldBundle == null)
    {
        LogMessage(LogLevel.Info, "oldBundle was null", 0, 0, "");
        return;
    }

    //loop through each email message - delete any older than 7 days
    for (int i = 0; i <= oldBundle.MessageCount - 1; i++)
    {
        //get the individual message
        Chilkat.Email email = oldBundle.GetEmail(i);

        LogMessage(LogLevel.Debug, "Checking seen messages", 0, 0, "");

        if (email.EmailDate < DateTime.Now.AddDays(KeepDays * -1))
        {
            success = imap.SetMailFlag(email, "Deleted", 1);
            if (success != true)
            {
                LogMessage(LogLevel.Info, imap.LastErrorText, 0, 0, "");
            }
            LogMessage(LogLevel.Debug, String.Format("Setting deleted flag for message subject:{0}", email.Subject), 0, 0, "");
            deletedMessageCount++;
        }
        else
        {
            LogMessage(LogLevel.Debug, String.Format("Email with subject:{0} does not qualify for deletion.", email.Subject), 0, 0, "");
        }
    }

    //delete the messages and close the e-mail
    if (deletedMessageCount > 0)
    {
        LogMessage(LogLevel.Debug, String.Format("Expunging {0} old messages...",deletedMessageCount), 0, 0, "");
        imap.ExpungeAndClose();
    }
    else
    {
        LogMessage(LogLevel.Debug, "No messages to delete.", 0, 0, "");
    }

}

Answer

Well that makes sense now. Thanks,

-Eric