请帮助我解决使用POP3协议检索电子邮件的问题

时间:2009-04-17 23:21:44

标签: c# compact-framework pop3

我正在使用C#和Microsoft .Net Compact Framework 1.0。我尝试使用System.Net.Sockets.NetworkStreamTcpClient类来实现POP3协议。我能够登录并接收电子邮件并使用某些电子邮件服务器保存附件。但是对于一些人来说,我一直遇到问题。

我通过发送List <Index>命令来阅读电子邮件的大小。在某些情况下,我的尺寸明显小于实际值。例如,对于相同的电子邮件:

Actual size: 577860, Returned size: 421096 using Exchange 2007
Actual size: 561005, Returned size: 560997 using Exchange 2003

为什么我没有得到合适的尺寸?以下是我正在使用的代码。

电子邮件的大小永远不会与StringBuilder程序结束时PopRead的大小相匹配。我无法可靠地阅读电子邮件,因为电子邮件大小不可靠,DataAvailable的{​​{1}}属性有时是假的,即使有更多数据可以读取。

我发现,当我尝试通过无线方式(使用数据计划)连接到电子邮件服务器时,NetworkStream属性更频繁,而不是通过activesync使用计算机的互联网连接时。

如果有帮助,电子邮件服务器是Exchange 2003和Exchange 2007.

DataAvailable

以下过程用于获取电子邮件的大小:

private bool POPRead(StringBuilder strBuffer, long lngFetchMailSize)
{
   const int bufferSize = 1024;

    byte[] inb;
    if (enc == null)
    {
        enc = new ASCIIEncoding();
    }

    try
    {
        if (lngFetchMailSize > 0 && lngFetchMailSize < (32 * bufferSize))
        {
            // limit the size of the buffer as the amount of memory
            // on Pocket PC is limited.
            inb = new byte[lngFetchMailSize];
        }
        else
        {
            inb = new byte[bufferSize];
        }
        Array.Clear(inb, 0, inb.Length);
        bool bMoreData = true;
        long iBytesRead = 0L;
        int bytesReadInThisRound = 0;

        int numberOfTimesZeroBytesRead = 0;

        while (bMoreData)
        {
            bytesReadInThisRound = this.nsPOP.Read(inb, 0, inb.Length);
            iBytesRead += bytesReadInThisRound;

            if (bytesReadInThisRound == 0)
            {
                numberOfTimesZeroBytesRead++;
            }
            else
            {//If on a retry the data read is not empty, reset the counter.
                numberOfTimesZeroBytesRead = 0;
            }

            strBuffer.Append(enc.GetString(inb, 0, bytesReadInThisRound));
            Array.Clear(inb, 0, bytesReadInThisRound);
            // DataAvailable sometimes gives false even though there is
            // more to be read.
            bMoreData = this.nsPOP.DataAvailable;
            // Use this number (5), since some servers sometimes give the size
            // of the email bigger than the actual size.
            if ((lngFetchMailSize != 0 && !bMoreData)
                && (iBytesRead < lngFetchMailSize)
                && numberOfTimesZeroBytesRead < 5)
            {
                bMoreData = true;
            }
        }
    }
    catch (Exception ex)
    {
        string errmessage = "Reading email Expected Size: " + lngFetchMailSize;
        LogException.LogError(ex, errmessage, false, "oePPop.POPRead");
        Error = ex.Message + " " + errmessage;
        return false;
    }
    finally
    {
        GC.Collect();
    }
    return true;
}

希望我提供解决问题所需的所有信息。任何正确方向的帮助或指针都会有很多帮助。

谢谢,
钱德拉。

3 个答案:

答案 0 :(得分:1)

您的错误可能在于您使用ASCIIEncoder。

来自MSDN

  

要转换的数据,例如数据   从流中读取,可以使用   仅在顺序块中。在这   大小写,或者数据量是多少   大,它需要分为   更小的块,应用程序应该   使用解码器或编码器   由GetDecoder方法提供或   分别是GetEncoder方法。

由于您一次只进行一点解码,因此可能会错误地解码部分流。

我会更改您的代码以使用decoder,或者立即读取整个消息,然后使用GetString()成员对其进行解码。

作为额外的健全性检查,您可以使用RETR&lt; index&gt;的消息大小。返回并查看它是否与LIST返回的内容相匹配。如果它们不匹配,我至少会使用RETR返回的内容。

答案 1 :(得分:0)

POP3是一个棘手的协议。这么多不同的服务器要处理,很多都有自己模糊不清的怪癖。如果这是一个生产应用程序,我会认真考虑购买经过全面测试的第三方组件。

答案 2 :(得分:0)

由于电子邮件应该以句号结尾,我会进行此比较以终止循环。

而不是

 if ((lngFetchMailSize != 0 && !bMoreData)
       && (iBytesRead < lngFetchMailSize)
       && numberOfTimesZeroBytesRead < 5)
  {
      bMoreData = true;
  }

我会把它写成

  if(!bMoreData 
    && strBuffer.ToString(strBuffer.Length - 5, 5) != "\r\n.\r\n")
  {
       bMoreData = true;
  }