收到的电子邮件损坏
Broken received emails
我通过简单的 IMAP 客户端收到带有附件的电子邮件:
class Program
{
static StreamWriter sw = null;
static TcpClient tcpc = null;
static SslStream ssl = null;
static string path;
static StringBuilder sb = new StringBuilder();
static byte[] dummy;
string username = "user";
string password = "pass";
static void Main(string[] args)
{
try
{
path = Environment.CurrentDirectory + "\emailresponse.txt";
if (System.IO.File.Exists(path))
System.IO.File.Delete(path);
using (sw = new System.IO.StreamWriter(System.IO.File.Create(path)))
using (tcpc = new System.Net.Sockets.TcpClient("imap.server.com", 993))
using (ssl = new System.Net.Security.SslStream(tcpc.GetStream()))
{
ssl.AuthenticateAsClient("imap.server.com");
receiveResponse("");
receiveResponse("$ LOGIN " + username + " " + password + "\r\n");
Console.WriteLine("enter the email number to fetch :");
int number = int.Parse(Console.ReadLine());
receiveResponse("$ FETCH " + number + " body[header]\r\n");
receiveResponse("$ FETCH " + number + " body[text]\r\n");
receiveResponse("$ LOGOUT\r\n");
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
static void receiveResponse(string command)
{
try
{
if (command != "")
{
if (tcpc.Connected)
{
dummy = Encoding.Default.GetBytes(command);
ssl.Write(dummy, 0, dummy.Length);
}
else
{
throw new ApplicationException("TCP CONNECTION DISCONNECTED");
}
}
ssl.Flush();
byte[] bigBuffer = new byte[1024*18];
int bites = ssl.Read(bigBuffer, 0, bigBuffer.Length);
byte[] buffer = new byte[bites];
Array.Copy(bigBuffer, 0, buffer, 0, bites);
sb.Append(Encoding.Default.GetString(buffer));
sw.WriteLine(sb.ToString());
sb = new StringBuilder();
}
catch (Exception ex)
{
throw new ApplicationException(ex.ToString());
}
}
}
一切正常,但如果电子邮件大小超过 ~19kb,无论缓冲区大小如何,内容都会被裁剪。如何解决?
如果您调用 Stream.Read(),它不保证它会读取您要求的字节数。它只保证它不会读取 比您请求的字节数多 并且它至少会读取 1 个字节,除非流达到 EOF (对于网络流,如果 Stream.Read() returns 0,则表示套接字已断开连接。
正如其他人指出的那样,您需要编写一个循环调用 Stream.Read() 直到您阅读完整的回复。
但是请注意,您不能盲目地编写一个循环,一遍又一遍地调用 Stream.Read() 直到 Read() returns 0,因为这会导致您的代码挂起。您需要在阅读时正确解析回复,以便计算您实际需要阅读的数据量,并在阅读完整回复后停止阅读。
为此,您需要阅读 rfc3501 并为其编写解析器。
由于在解析消息内容之前无法轻松地将 byte[] 数据转换为字符串(消息中的每个 text/* 部分可能以不同的字符集编码),因此您将需要编写您的解析器,使其解析字节数组而不是字符串。
如果这听起来对您来说工作量太大,您可能需要考虑使用 MailKit.
等库
解决方案是我必须重复请求 receiveResponse("$ FETCH " + number + " body[text]\r\n")
直到我获得所有数据片段。问题是我确实在 receiveResponse
而不是主块内循环。
我通过简单的 IMAP 客户端收到带有附件的电子邮件:
class Program
{
static StreamWriter sw = null;
static TcpClient tcpc = null;
static SslStream ssl = null;
static string path;
static StringBuilder sb = new StringBuilder();
static byte[] dummy;
string username = "user";
string password = "pass";
static void Main(string[] args)
{
try
{
path = Environment.CurrentDirectory + "\emailresponse.txt";
if (System.IO.File.Exists(path))
System.IO.File.Delete(path);
using (sw = new System.IO.StreamWriter(System.IO.File.Create(path)))
using (tcpc = new System.Net.Sockets.TcpClient("imap.server.com", 993))
using (ssl = new System.Net.Security.SslStream(tcpc.GetStream()))
{
ssl.AuthenticateAsClient("imap.server.com");
receiveResponse("");
receiveResponse("$ LOGIN " + username + " " + password + "\r\n");
Console.WriteLine("enter the email number to fetch :");
int number = int.Parse(Console.ReadLine());
receiveResponse("$ FETCH " + number + " body[header]\r\n");
receiveResponse("$ FETCH " + number + " body[text]\r\n");
receiveResponse("$ LOGOUT\r\n");
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
static void receiveResponse(string command)
{
try
{
if (command != "")
{
if (tcpc.Connected)
{
dummy = Encoding.Default.GetBytes(command);
ssl.Write(dummy, 0, dummy.Length);
}
else
{
throw new ApplicationException("TCP CONNECTION DISCONNECTED");
}
}
ssl.Flush();
byte[] bigBuffer = new byte[1024*18];
int bites = ssl.Read(bigBuffer, 0, bigBuffer.Length);
byte[] buffer = new byte[bites];
Array.Copy(bigBuffer, 0, buffer, 0, bites);
sb.Append(Encoding.Default.GetString(buffer));
sw.WriteLine(sb.ToString());
sb = new StringBuilder();
}
catch (Exception ex)
{
throw new ApplicationException(ex.ToString());
}
}
}
一切正常,但如果电子邮件大小超过 ~19kb,无论缓冲区大小如何,内容都会被裁剪。如何解决?
如果您调用 Stream.Read(),它不保证它会读取您要求的字节数。它只保证它不会读取 比您请求的字节数多 并且它至少会读取 1 个字节,除非流达到 EOF (对于网络流,如果 Stream.Read() returns 0,则表示套接字已断开连接。
正如其他人指出的那样,您需要编写一个循环调用 Stream.Read() 直到您阅读完整的回复。
但是请注意,您不能盲目地编写一个循环,一遍又一遍地调用 Stream.Read() 直到 Read() returns 0,因为这会导致您的代码挂起。您需要在阅读时正确解析回复,以便计算您实际需要阅读的数据量,并在阅读完整回复后停止阅读。
为此,您需要阅读 rfc3501 并为其编写解析器。
由于在解析消息内容之前无法轻松地将 byte[] 数据转换为字符串(消息中的每个 text/* 部分可能以不同的字符集编码),因此您将需要编写您的解析器,使其解析字节数组而不是字符串。
如果这听起来对您来说工作量太大,您可能需要考虑使用 MailKit.
等库解决方案是我必须重复请求 receiveResponse("$ FETCH " + number + " body[text]\r\n")
直到我获得所有数据片段。问题是我确实在 receiveResponse
而不是主块内循环。