แนบไฟล์จาก MemoryStream ไปยัง MailMessage ใน C #


113

ฉันกำลังเขียนโปรแกรมเพื่อแนบไฟล์กับอีเมล ขณะนี้ฉันกำลังบันทึกไฟล์โดยใช้FileStreamลงในดิสก์จากนั้นฉันใช้ไฟล์

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

Attachmentฉันไม่ต้องการที่จะเก็บไว้ในไฟล์ดิสก์ผมต้องการที่จะไฟล์เก็บไว้ในหน่วยความจำและหน่วยความจำจากกระแสผ่านนี้

คำตอบ:


104

นี่คือโค้ดตัวอย่าง

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คุณต้องระบุนามสกุลที่ถูกต้องใน FileName เช่น"myFile.pdf"


ฉันใช้ PDF วิธีส่งประเภทนี้ไปยัง System.Net.Mime.ContentType ct = System.Net.Mime.ContentType ใหม่ (System.Net.Mime.MediaTypeNames.Text.Plain);
Zain Ali

3
คุณจำเป็นต้องใช้System.Net.Mime.MediaTypeNames.Application.Pdf
Waqas Raja

5
writer.Disopose()ยังเร็วเกินไปสำหรับวิธีแก้ปัญหาของฉัน แต่อย่างอื่นเป็นตัวอย่างที่ดี
Kazimierz Jawor

7
ฉันค่อนข้างมั่นใจว่าควรมีms.Position = 0;ก่อนสร้างไฟล์แนบ
Kenny Evitt

94

การเข้าสายเล็กน้อย - แต่หวังว่าจะยังมีประโยชน์กับใครบางคนที่นั่น: -

นี่คือตัวอย่างข้อมูลที่เรียบง่ายสำหรับการส่งสตริงในหน่วยความจำเป็นไฟล์แนบอีเมล (ไฟล์ 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)


30
สำหรับผู้มาใหม่สิ่งสำคัญสำหรับฉันคือการตั้งค่าstream.position = 0;
mtbennett

3
+1 เพื่อการใช้งานที่เหมาะสมในการใช้ () - สิ่งที่ดูเหมือนจะขาดหายไปจากตัวอย่างและตัวอย่างออนไลน์อยู่เสมอ (รวมถึงคำตอบที่ยอมรับสำหรับคำถามนี้)
Jay Querido

2
ขอขอบคุณที่ @mtbennet นั่นก็เป็นปัญหาของฉัน - stream.Position=0การตั้งค่า
Icarus

การตั้งค่าประเภท MIME ทำอะไรได้บ้างที่นี่? บางสิ่งบางอย่างสำหรับแอปไคลเอนต์อีเมล?
xr280xr

@ xr280xr - ถูกต้อง พารามิเตอร์นี้ไม่จำเป็นต้องใช้ แต่การรวมพารามิเตอร์นี้ควรช่วยให้ไคลเอนต์อีเมลของผู้รับจัดการกับไฟล์แนบได้อย่างสมเหตุสมผล docs.microsoft.com/en-us/dotnet/api/…
tarn

28

เนื่องจากฉันไม่พบการยืนยันสิ่งนี้จากที่ใดเลยฉันจึงทดสอบว่าการกำจัด MailMessage และ / หรือวัตถุสิ่งที่แนบมาจะกำจัดสตรีมที่โหลดลงในสิ่งเหล่านี้ตามที่ฉันคาดไว้หรือไม่

ปรากฏพร้อมกับการทดสอบต่อไปนี้ว่าเมื่อกำจัด 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);

ไอ้ที่ฉลาด รหัสหนึ่งบรรทัดและคุณสามารถเพิ่มไฟล์รูปภาพลงในอีเมลเป็นไฟล์แนบได้ เคล็ดลับดีๆ!
Mike Gledhill

ฉันหวังว่านี่จะเป็นเอกสารจริง การทดสอบ / ยืนยันพฤติกรรมนี้ของคุณมีประโยชน์ แต่หากไม่ได้อยู่ในเอกสารอย่างเป็นทางการก็ยากที่จะเชื่อถือว่าจะเป็นเช่นนั้นเสมอไป อย่างไรก็ตามขอบคุณสำหรับการทดสอบ
Lucas

ความพยายามที่ดีและ @thymine วิจัย
vibs2006

1
จัดเรียงเป็นเอกสารหากแหล่งอ้างอิงมีค่า mailmessage.disposeโทรattachments.disposeซึ่งในการเปลี่ยนสายทิ้งในแต่ละสิ่งที่แนบมาซึ่งใน mimepart, ปิดกระแส
Cee McSharpface

ขอบคุณ. ฉันคิดว่าข้อความเมลควรจะทำและจำเป็นต้องใช้เพราะฉันกำลังสร้างข้อความของฉันในชั้นเรียนที่แตกต่างจากที่ที่ส่งข้อความจริง
xr280xr

20

หากคุณต้องการเพิ่ม. 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);

ใช้เวลาหลายชั่วโมงในการส่ง pdf ซึ่งได้ผลอย่างมีเสน่ห์
dijam

12

หากสิ่งที่คุณทำคือการแนบสตริงคุณสามารถทำได้ใน 2 บรรทัด:

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

ฉันไม่สามารถให้ของฉันทำงานโดยใช้เซิร์ฟเวอร์อีเมลของเรากับ StreamWriter ได้
ฉันคิดว่าอาจเป็นเพราะด้วย StreamWriter คุณไม่มีข้อมูลคุณสมบัติไฟล์จำนวนมากและเซิร์ฟเวอร์ของเราอาจไม่ชอบสิ่งที่ขาดหายไป
ด้วย Attachment.CreateAttachmentFromString () มันสร้างทุกสิ่งที่ฉันต้องการและใช้งานได้ดี!

มิฉะนั้นฉันขอแนะนำให้นำไฟล์ของคุณที่อยู่ในหน่วยความจำและเปิดโดยใช้ MemoryStream (byte []) และข้าม StreamWriter ทั้งหมดเข้าด้วยกัน


2

ฉันถามคำถามนี้เพราะฉันต้องการแนบไฟล์ Excel ที่ฉันสร้างผ่านรหัสและพร้อมใช้งานเป็นMemoryStreamไฟล์. ฉันสามารถแนบไปกับข้อความเมลได้ แต่มันถูกส่งเป็นไฟล์ 64Bytes แทนที่จะเป็น ~ 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ให้ฉันส่งข้อความด้วยขนาดไฟล์แนบที่ถูกต้อง


2

ใช้สตรีมหน่วยความจำเปิดอื่น ๆ :

ตัวอย่างสำหรับ lauch pdf และส่ง pdf ใน MVC4 C # Controller

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

stream.Position=0; เป็นสายที่ช่วยฉัน ถ้าไม่มีมันการปรับแต่งของฉันก็แค่ 504 ไบต์ที่ติดตั้งจากบาง kBs
Abdul Hameed

-6

ฉันคิดว่ารหัสนี้จะช่วยคุณได้:

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

5
-1 คำตอบนี้โหลดไฟล์แนบจากดิสก์โดยใช้ตัวสร้างสิ่งที่แนบมา (string fileName) OP ระบุโดยเฉพาะว่าเขาไม่ต้องการโหลดจากดิสก์ นอกจากนี้นี่เป็นเพียงรหัสที่คัดลอกมาจากลิงก์ในคำตอบของ Red Swan
Walter Stabosz

แนบไฟล์สตรีมก็ไม่ได้รับการกำจัดเช่นกัน
Sameh
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.