使用MailKit获取MimeMessage对象完整内容长度的方法咨询
关于MailKit中MimeMessage预获取发送内容长度的解答
目前MailKit库没有原生提供无需序列化即可直接获取MimeMessage完整发送内容长度的API。因为MIME邮件的最终发送内容包含动态生成的头字段、编码后的正文、附件边界标识、换行符标准化等多部分动态内容,无法在不执行序列化逻辑的前提下100%准确计算总长度。
你当前设计的实现方案存在两处明显问题:
- 仅统计了
Body部分的大小,没有包含邮件头(发件人、收件人、主题、自定义头、MIME版本声明等)的长度,计算结果会比实际发送的总大小小很多 - 不需要将序列化后的字节转Base64再计算长度:
MemoryStream.Length本身就已经是序列化后的字节总数,转Base64会让计算结果比实际值大33%左右,完全不符合实际大小统计需求
低内存占用优化方案(推荐)
你可以实现一个仅计数不实际存储数据的虚拟流,避免将整个邮件内容加载到内存中,开销几乎可以忽略,同时能拿到准确的总长度:
// 仅计数的虚拟流,不实际存储字节数据 public class DummyCountStream : Stream { public long TotalBytesWritten { get; private set; } public override void Write(byte[] buffer, int offset, int count) { TotalBytesWritten += count; } public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { TotalBytesWritten += count; return Task.CompletedTask; } // 其余Stream抽象成员无需实现,MimeMessage序列化仅会调用Write/WriteAsync方法 public override bool CanRead => false; public override bool CanSeek => false; public override bool CanWrite => true; public override long Length => throw new NotImplementedException(); public override long Position { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } public override void Flush() { } public override int Read(byte[] buffer, int offset, int count) => throw new NotImplementedException(); public override long Seek(long offset, SeekOrigin origin) => throw new NotImplementedException(); public override void SetLength(long value) => throw new NotImplementedException(); }
使用方式如下:
var counter = new DummyCountStream(); // 调用整个MimeMessage的序列化方法,而非仅序列化Body await mailMessage.WriteToAsync(counter); // 得到的长度即为实际发送的邮件总字节数 long curMessageLength = counter.TotalBytesWritten;
如果不想额外实现虚拟流,也可以用简化版的正确写法:
using (var memory = new MemoryStream()) { await mailMessage.WriteToAsync(memory); long curMessageLength = memory.Length; }
该方案仅会在内存中临时存储整份邮件内容,对于常规大小的邮件开销在可接受范围内。
内容的提问来源于stack exchange,提问作者Jay
相关产品推荐
相关产品推荐

