构造多部分 MIME 消息而不将其保存在内存中

Construct a multipart MIME message without holding it in memory

我想根据我从某些流(例如打开的文件句柄)获得的部分数据创建一个多部分 MIME 消息,并且我希望生成的多部分 MIME 消息通过流(例如网络端口)发送出去作为 HTTP 连接的一部分)。

但是,这些部分的大小有很多 GB,所以我不想将它们保存在内存中,我也不希望多部分 MIME 消息需要完全保存在内存中。

那么我如何创建多部分 MIME 消息而不将它保存在内存中,即在部分中流式传输并让它流出构造的消息'on the fly'?

我想使用第 3 方 MIME 库,但不知道是否支持这样的流式传输,而且我不愿意自己编写。

有什么推荐的做法吗?

MimeKit 支持从磁盘而不是从内存流式传输 MimeParts 的内容,但我不确定是否有任何 HTTP 库会为您提供原始套接字或 NetworkStream(或 SslStream)来写入消息。

假设 HTTP 库不是限制因素,您可以像这样在 MimeKit 中创建 MimePart:

var part = new MimePart ("application", "octet-stream") {
    Content = new MimeContent (File.OpenRead ("large-file.dat")),
    ContentTransferEncoding = ContentENcoding.Base64,
    FileName = "large-file.dat"
};

您可以像这样创建多部分:

var multipart = new Multipart ("mixed");
multipart.Add (part);

您可以像这样将多部分设置为 MimeMessage 的正文(尽管我不确定您是否真的需要 MimeMessage 容器来完成您打算执行的操作):

message.Body = multipart;

并且您可以像这样将消息(或多部分)流式传输到网络流(或任何类型的流):

message.WriteTo (stream);

如果您需要确保即使在 Unix 系统上也能将消息转换为使用 CRLF,您可以这样做:

var options = FormatOptions.Default.Clone ();
options.NewLineFormat = NewLineFormat.Dos;

message.WriteTo (options, stream);

这会将消息数据推送到一个过滤器,该过滤器将在将行尾写入输出流时转换行尾(如果需要转换)。

由于消息数据以大约 4k 块的形式分块,因此它应该符合您的要求。

如果您还有其他问题,请在 GitHub 上找到我的电子邮件地址(同一个别名,我是 MimeKit/MailKit 的作者,所以应该很容易找到)并给我发一封电子邮件.我很乐意回答您关于如何执行此操作的任何问题。

事实上,MimeKit 的设计正是为了做你想做的事,并确保一切正常,我编写了 MailKit 的原始 SmtpClient。然后我在周末写了 Pop3Client 来测试我是否可以解析直接从套接字读取的消息。

是的,它可以做你需要它做的事。

经过进一步研究(受上述 MimeKit 示例启发),.Net HTTP 类 以与 MimeKit 类似的方式支持我正在寻找的内容。

创建一个 MultipartContent 并使用 StreamContent 添加部分,然后使用 MultipartContent.ReadAsStreamAsync 获取多部分消息的流,直到多部分流需要它时才会读取部分流。这意味着(从监控进程大小)原始部分在任何时候都不会完全在内存中,多部分消息也不会。