【问题标题】:Please help with my problems retrieving email using POP3 protocol请帮助我解决使用 POP3 协议检索电子邮件的问题
【发布时间】:2009-04-17 23:21:44
【问题描述】:

我正在使用 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

为什么我总是找不到合适的尺寸?以下是我正在使用的代码。

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

我观察到DataAvailable 属性在我尝试通过无线方式(使用数据计划)连接到电子邮件服务器时比在通过 activesync 使用计算机的互联网连接时更常见。

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

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;
}

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

private long GetMailSize(int index)
{
    StringBuilder strBuffer = new StringBuilder();
    const string LISTError = "Unable to read server's reply for LIST command";
    if ((this.POPServer != null) && (this.nsPOP != null))
    {
        if (!this.POPWrite("LIST " + index))
        {
            return -1L;
        }
        if (!this.POPRead(strBuffer))
        {
            this.Error = LISTError;
            return -1L;
        }
        if (!this.IsOK(strBuffer))
        {
            return -1L;
        }
        string strReturned = strBuffer.ToString();
        int pos1 = strReturned.IndexOf(" ", 3);
        if (pos1 == -1)
        {
            this.Error = LISTError;
            return -1L;
        }
        int pos2 = strReturned.IndexOf(" ", (int)(pos1 + 1));
        if (pos2 == -1)
        {
            this.Error = LISTError;
            return -1L;
        }
        int pos3 = strReturned.IndexOf("\r\n", (int)(pos2 + 1));
        if (pos3 == -1)
        {
            this.Error = LISTError;
            return -1L;
        }
        long mailSize = 0;
        Int64.TryParse(strBuffer.ToString(pos2 + 1, pos3 - (pos2 + 1)).Trim(), out mailSize);
        return mailSize;
    }
    this.Error = NotConnectedError;
    return -1L;
}

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

谢谢,
钱德拉。

【问题讨论】:

    标签: c# compact-framework pop3


    【解决方案1】:

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

    来自MSDN

    要转换的数据,如data 从流中读取,可用 仅在顺序块中。在这个 情况,或者如果数据量如此 大到需要分成 较小的块,应用程序应该 使用解码器或编码器 由 GetDecoder 方法提供或 GetEncoder 方法。

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

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

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

    【讨论】:

      【解决方案2】:

      POP3 是一个棘手的协议。有这么多不同的服务器要处理,许多都有自己晦涩难懂的怪癖。如果这是一个生产应用程序,我会认真考虑购买经过彻底测试的第 3 方组件。

      【讨论】:

      • 您好,我尝试了几个组件(试用版),但没有太大帮助。一些不断抛出的异常,当我不得不下载一个大的(大约 3 MB)附件时,我一直遇到 OutOfMemory 异常。如果你有建议就好了。谢谢,钱德拉
      【解决方案3】:

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

      代替

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

      我会这样写

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

      【讨论】:

        猜你喜欢
        • 2011-08-23
        • 2012-10-19
        • 1970-01-01
        • 2014-03-02
        • 1970-01-01
        • 1970-01-01
        • 2022-05-06
        • 2018-03-17
        • 2021-09-17
        相关资源
        最近更新 更多