C# 将MemoryStream中的文件附加到C中的邮件消息#

C# 将MemoryStream中的文件附加到C中的邮件消息#,c#,email,smtp,memorystream,C#,Email,Smtp,Memorystream,我正在编写一个程序,将文件附加到电子邮件。目前我正在使用FileStream将文件保存到磁盘中,然后使用 System.Net.Mail.MailMessage.Attachments.Add( new System.Net.Mail.Attachment("file name")); 我不想将文件存储在磁盘中,我想将文件存储在内存中,并从内存流将其传递到附件以下是示例代码 System.IO.MemoryStream ms = new System.IO.MemoryStream(

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

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

我不想将文件存储在磁盘中,我想将文件存储在内存中,并从内存流将其传递到
附件

以下是示例代码

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


基于Mime类型您需要在文件名中指定正确的扩展名,例如
“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 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文件)


StreamWriter和底层流在消息发送后才应被释放(以避免
ObjectDisposedException:无法访问关闭的流
)。

如果您所做的只是附加一个字符串,则只需两行即可:

mail.Attachments.Add(Attachment.CreateAttachmentFromString("1,2,3", "text/csv");
mail.Attachments.Last().ContentDisposition.FileName = "filename.csv";
我无法使用带有StreamWriter的邮件服务器工作。
我想可能是因为StreamWriter丢失了很多文件属性信息,可能是我们的服务器不喜欢丢失的内容。
通过Attachment.CreateAttachmentFromString(),它创建了我需要的一切,效果非常好


否则,我建议您使用内存流(字节[])打开内存中的文件,并同时跳过StreamWriter。

如果您确实要添加.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);

我回答这个问题是因为我需要附加一个通过代码生成的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);

设置附件.ContentDisposition.Size的值让我发送附件大小正确的邮件。

使用其他打开的memorystream:

MVC4 C#控制器中的lauch pdf和send 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);
    }


我正在使用PDF如何将此类型传递给System.Net.Mime.ContentType ct=new System.Net.Mime.ContentType(System.Net.Mime.MediaTypeNames.Text.Plain);您需要使用
System.Net.Mime.MediaTypeNames.Application.Pdf
writer.disospose()
对于我的解决方案来说太早了,但所有其他的都是很好的例子。我非常确定应该有一个
ms.Position=0创建附件之前。-1此答案使用附件(字符串文件名)构造函数从磁盘加载附件。OP特别声明他不想从磁盘加载。此外,这只是从红天鹅的答案中的链接粘贴的代码副本。attachFile stream也没有处理。对于任何新来者,我的关键是设置
stream.position=0+1,以便正确使用(),这是联机示例和代码片段(包括此问题的公认答案)中似乎总是缺少的内容。感谢@m.t.bennet,这也是我的问题设置
stream.Position=0
。在这里设置MIME类型实际上做什么?电子邮件客户端应用程序的内容?@xr280xr-正确。此参数实际上不是必需的,但包括它应有助于收件人的电子邮件客户端明智地处理附件。该死,真聪明。一行代码,您可以将图像文件作为附件添加到电子邮件中。好提示!我希望这真的有记录在案。您对这种行为的测试/验证是有用的,但如果没有官方文档,很难相信这种情况会一直存在。不管怎样,谢谢你的测试。很好的努力和研究@Thyminine如果参考源计算的话,它是有记录的。依次呼叫的呼叫,在mimepart中,谢谢。我认为邮件信息应该做到这一点,并且需要做到这一点,因为我在不同的类别中创建信息,而不是在实际发送信息的地方。花几个小时发送pdf,这很有魅力!谢谢这个代码片段对我很有用。
stream.Position=0是帮助我的那句话。如果没有它,我的地址只有504字节,安装了一些kbs。这种方法不需要你在发送之前保持流的打开状态,这对我创建电子邮件的方式非常有帮助。非常感谢。
        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);
    }