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

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

System.Net.Mail.MailMessage.Attachments.Add(
new System.Net.Mail.Attachment("file name"));

我不想存储在磁盘文件,我想存储在内存中的文件,并从内存流传递到 Attachment

202976 次浏览

下面是示例代码。

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();

编辑1

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

基于 哑剧类型,您需要在 FileName 中为实例 "myFile.pdf"指定正确的扩展名

我认为这个代码会帮助你:

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Net.Mail;


public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{


}


protected void btnSubmit_Click(object sender, EventArgs e)
{
try
{
MailAddress SendFrom = new MailAddress(txtFrom.Text);
MailAddress SendTo = new MailAddress(txtTo.Text);


MailMessage MyMessage = new MailMessage(SendFrom, SendTo);


MyMessage.Subject = txtSubject.Text;
MyMessage.Body = txtBody.Text;


Attachment attachFile = new Attachment(txtAttachmentPath.Text);
MyMessage.Attachments.Add(attachFile);


SmtpClient emailClient = new SmtpClient(txtSMTPServer.Text);
emailClient.Send(MyMessage);


litStatus.Text = "Message Sent";
}
catch (Exception ex)
{
litStatus.Text = ex.ToString();
}
}
}

由于在任何地方都找不到确认信息,所以我测试了处理邮件消息和/或附件对象是否会像预期的那样处理加载到它们中的流。

通过以下测试,确实可以看出,当释放 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);

有点晚了-但希望对某些人仍然有用:-

下面是一个简化的代码片段,用于将内存中的字符串作为电子邮件附件(在这个特殊情况下是一个 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);
}

直到消息发送之后,才应释放 StreamWriter 和基础流(以避免 ObjectDisposedException: Cannot access a closed Stream)。

如果你所做的只是附加一个字符串,你只需要两行就可以做到:

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

我无法使用我们的邮件服务器和 StreamWriter 工作。
我想可能是因为 StreamWriter 丢失了很多文件属性信息,也可能是我们的服务器不喜欢丢失的内容。
通过 Attaching.CreateAttachmentFromString () ,它创建了我需要的所有东西,并且工作得非常好!

否则,我建议使用存储在内存中的文件并使用 MemoryStream (byte [])打开它,然后一起跳过 StreamWriter。

如果您实际上想要添加一个。我发现有必要将内存流的位置设置为零。

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

我之所以选择这个问题,是因为我需要附加一个通过代码生成的 Excel 文件,它可以作为 MemoryStream使用。我可以附加到邮件消息,但它被发送为64字节的文件,而不是一个 ~ 6KB,因为它的意思。所以,对我有效的解决办法是这样的:

MailMessage mailMessage = new MailMessage();
Attachment attachment = new Attachment(myMemorySteam, new ContentType(MediaTypeNames.Application.Octet));


attachment.ContentDisposition.FileName = "myFile.xlsx";
attachment.ContentDisposition.Size = attachment.Length;


mailMessage.Attachments.Add(attachment);

通过设置 attachment.ContentDisposition.Size的值,我可以发送具有正确附件大小的消息。

使用其他开放内存流:

例如,在 MVC4C # 控制器中启动 pdf 并发送 pdf

        public void ToPdf(string uco, int idAudit)
{
Response.Clear();
Response.ContentType = "application/octet-stream";
Response.AddHeader("content-disposition", "attachment;filename= Document.pdf");
Response.Buffer = true;
Response.Clear();


//get the memorystream pdf
var bytes = new MisAuditoriasLogic().ToPdf(uco, idAudit).ToArray();


Response.OutputStream.Write(bytes, 0, bytes.Length);
Response.OutputStream.Flush();


}




public ActionResult ToMail(string uco, string filter, int? page, int idAudit, int? full)
{
//get the memorystream pdf
var bytes = new MisAuditoriasLogic().ToPdf(uco, idAudit).ToArray();


using (var stream = new MemoryStream(bytes))
using (var mailClient = new SmtpClient("**YOUR SERVER**", 25))
using (var message = new MailMessage("**SENDER**", "**RECEIVER**", "Just testing", "See attachment..."))
{


stream.Position = 0;


Attachment attach = new Attachment(stream, new System.Net.Mime.ContentType("application/pdf"));
attach.ContentDisposition.FileName = "test.pdf";


message.Attachments.Add(attach);


mailClient.Send(message);
}


ViewBag.errMsg = "Documento enviado.";


return Index(uco, filter, page, idAudit, full);
}