将MemoryStream中的文件附加到C#中的MailMessage

Zai*_*Ali 105 c# email smtp memorystream

我正在编写一个程序来将文件附加到电子邮件中.目前我正在使用FileStream磁盘保存文件,然后我使用

System.Net.Mail.MailMessage.Attachments.Add(
    new System.Net.Mail.Attachment("file name")); 
Run Code Online (Sandbox Code Playgroud)

我不想将文件存储在磁盘中,我想将文件存储在内存中,并从内存流传递给它Attachment.

Waq*_*aja 97

这是示例代码.

System.IO.MemoryStream ms = new System.IO.MemoryStream();
System.IO.StreamWriter writer = new System.IO.StreamWriter(ms);
writer.Write("Hello its my sample file");
writer.Flush();
writer.Dispose();
ms.Position = 0;

System.Net.Mime.ContentType ct = new System.Net.Mime.ContentType(System.Net.Mime.MediaTypeNames.Text.Plain);
System.Net.Mail.Attachment attach = new System.Net.Mail.Attachment(ms, ct);
attach.ContentDisposition.FileName = "myFile.txt";

// I guess you know how to send email with an attachment
// after sending email
ms.Close();
Run Code Online (Sandbox Code Playgroud)

编辑1

您可以通过System.Net.Mime.MimeTypeNames指定其他文件类型 System.Net.Mime.MediaTypeNames.Application.Pdf

基于Mime Type,您需要在FileName中指定正确的扩展名"myFile.pdf"

  • 我很确定在创建附件之前应该有一个`ms.Position = 0;`. (6认同)
  • 您需要使用`System.Net.Mime.MediaTypeNames.Application.Pdf` (2认同)
  • `writer.Disopose()`对于我的解决方案来说太早了,但另外一个就是很好的例子. (2认同)

tra*_*arn 91

有点迟到 - 但希望对那里的人有用: -

这是一个简化的片段,用于将内存中的字符串作为电子邮件附件发送(在此特定情况下为CSV文件).

using (var stream = new MemoryStream())
using (var writer = new StreamWriter(stream))    // using UTF-8 encoding by default
using (var mailClient = new SmtpClient("localhost", 25))
using (var message = new MailMessage("me@example.com", "you@example.com", "Just testing", "See attachment..."))
{
    writer.WriteLine("Comma,Seperated,Values,...");
    writer.Flush();
    stream.Position = 0;     // read from the start of what was written

    message.Attachments.Add(new Attachment(stream, "filename.csv", "text/csv"));

    mailClient.Send(message);
}
Run Code Online (Sandbox Code Playgroud)

在发送消息之后(避免ObjectDisposedException: Cannot access a closed Stream),不应丢弃StreamWriter和底层流.

  • 对于任何新手来说,关键是设置`stream.position = 0;` (30认同)
  • 适当使用using()的+1 - 在网上的例子和片段中似乎总是缺少的东西(包括这个问题的接受答案). (3认同)
  • 感谢@mtbennet这也是我的问题 - 设置`stream.Position = 0`. (2认同)

Thy*_*ine 25

由于我无法在任何地方找到这方面的确认,我测试了如果处理MailMessage和/或Attachment对象会处理加载到它们中的流,正如我预期的那样.

通过以下测试确实显示,当放置MailMessage时,用于创建附件的所有流也将被丢弃.因此,只要您处置MailMessage,创建它的流就不需要处理.

MailMessage mail = new MailMessage();
//Create a MemoryStream from a file for this test
MemoryStream ms = new MemoryStream(File.ReadAllBytes(@"C:\temp\test.gif"));

mail.Attachments.Add(new System.Net.Mail.Attachment(ms, "test.gif"));
if (mail.Attachments[0].ContentStream == ms) Console.WriteLine("Streams are referencing the same resource");
Console.WriteLine("Stream length: " + mail.Attachments[0].ContentStream.Length);

//Dispose the mail as you should after sending the email
mail.Dispose();
//--Or you can dispose the attachment itself
//mm.Attachments[0].Dispose();

Console.WriteLine("This will throw a 'Cannot access a closed Stream.' exception: " + ms.Length);
Run Code Online (Sandbox Code Playgroud)

  • 如果参考来源重要的话,它是有记录的。[mailmessage.dispose](https://referencesource.microsoft.com/#System/net/System/Net/mail/MailMessage.cs,280) 调用 [attachments.dispose](https://referencesource.microsoft.com/ #System/net/System/Net/mail/AttachmentCollection.cs,19) 依次调用[在每个附件上进行处理](https://referencesource.microsoft.com/#System/net/System/Net/mail/Attachment .cs,60),在 mimepart 中,[关闭流](https://referencesource.microsoft.com/#System/net/System/Net/mail/MimePart.cs,28)。 (2认同)

Jas*_*ick 17

如果你真的想要添加.pdf,我发现还需要将内存流的位置设置为零.

var memStream = new MemoryStream(yourPdfByteArray);
memStream.Position = 0;
var contentType = new System.Net.Mime.ContentType(System.Net.Mime.MediaTypeNames.Application.Pdf);
var reportAttachment = new Attachment(memStream, contentType);
reportAttachment.ContentDisposition.FileName = "yourFileName.pdf";
mailMessage.Attachments.Add(reportAttachment);
Run Code Online (Sandbox Code Playgroud)


Mik*_*Vee 12

如果你正在做的只是附加一个字符串,你可以只用两行:

mail.Attachments.Add(Attachment.CreateAttachmentFromString("1,2,3", "text/csv");
mail.Attachments.Last().ContentDisposition.FileName = "filename.csv";
Run Code Online (Sandbox Code Playgroud)

我无法通过StreamWriter使用我们的邮件服务器让我的工作.
我想也许是因为使用StreamWriter你会丢失很多文件属性信息,也许我们的服务器不喜欢丢失的内容.
使用Attachment.CreateAttachmentFromString(),它创建了我需要的一切并且工作得很好!

否则,我建议将你的文件放在内存中并使用MemoryStream(byte [])打开它,并一起跳过StreamWriter.