Đính kèm tệp từ MemoryStream vào MailMessage trong C #


113

Tôi đang viết một chương trình để đính kèm một tập tin vào email. Hiện tại tôi đang lưu tệp bằng cách sử dụng FileStreamvào đĩa và sau đó tôi sử dụng

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

Tôi không muốn lưu tệp trong đĩa, tôi muốn lưu tệp trong bộ nhớ và từ luồng bộ nhớ chuyển tệp này sang Attachment.

Câu trả lời:


104

Đây là mã mẫu.

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

Chỉnh sửa 1

Bạn có thể chỉ định các loại tệp khác bằng System.Net.Mime.MimeTypeNames như System.Net.Mime.MediaTypeNames.Application.Pdf

Dựa trên Mime Type, bạn cần chỉ định phần mở rộng chính xác trong FileName chẳng hạn"myFile.pdf"


Tôi đang sử dụng PDF Làm thế nào để chuyển loại này sang System.Net.Mime.ContentType ct = new System.Net.Mime.ContentType (System.Net.Mime.MediaTypeNames.Text.Plain);
Zain Ali

3
Bạn cần sử dụngSystem.Net.Mime.MediaTypeNames.Application.Pdf
Waqas Raja

5
writer.Disopose()là quá sớm cho giải pháp của tôi nhưng tất cả những điều khác là ví dụ tuyệt vời.
Kazimierz Jawor

7
Tôi khá chắc chắn nên có một ms.Position = 0;trước khi tạo tệp đính kèm.
Kenny Evitt

94

Mục nhập hơi muộn - nhưng hy vọng vẫn hữu ích cho ai đó ngoài kia: -

Đây là đoạn mã đơn giản để gửi chuỗi trong bộ nhớ dưới dạng tệp đính kèm email (tệp CSV trong trường hợp cụ thể này).

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 và luồng bên dưới sẽ không được xử lý cho đến khi thư được gửi đi (tránh ObjectDisposedException: Cannot access a closed Stream).


30
Đối với bất kỳ người mới, chìa khóa đối với tôi là thiết lậpstream.position = 0;
mtbennett

3
+1 để sử dụng thích hợp việc sử dụng () - thứ mà dường như luôn bị thiếu trong các ví dụ và đoạn trích trực tuyến (bao gồm cả câu trả lời được chấp nhận cho câu hỏi này).
Jay Querido

2
Cảm ơn @mtbennet đó cũng là vấn đề của tôi - thiết lập stream.Position=0.
Icarus

Đặt kiểu MIME thực sự làm gì ở đây? Một cái gì đó cho ứng dụng khách e-mail?
xr280xr

@ xr280xr - Đúng. Thông số này không thực sự bắt buộc, nhưng việc bao gồm nó sẽ giúp ứng dụng email khách của người nhận xử lý tệp đính kèm một cách hợp lý. docs.microsoft.com/en-us/dotnet/api/…
yên tĩnh

28

Vì tôi không thể tìm thấy xác nhận về điều này ở bất cứ đâu, tôi đã kiểm tra xem việc hủy bỏ MailMessage và / hoặc đối tượng Tệp đính kèm sẽ hủy luồng được tải vào chúng như tôi mong đợi có xảy ra hay không.

Với thử nghiệm sau, dường như khi xử lý MailMessage, tất cả các luồng được sử dụng để tạo tệp đính kèm cũng sẽ bị xử lý. Vì vậy, miễn là bạn loại bỏ MailMessage của mình, các luồng được tạo ra nó không cần phải xử lý ngoài điều đó.

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

Chết tiệt, thật thông minh. Một dòng mã và bạn có thể thêm tệp hình ảnh vào email dưới dạng tệp đính kèm. Mẹo hay!
Mike Gledhill

Tôi ước điều này thực sự được ghi lại. Việc kiểm tra / xác minh của bạn về hành vi này là hữu ích, nhưng nếu không có trong tài liệu chính thức thì rất khó để tin rằng điều này sẽ luôn xảy ra. Dù sao, cảm ơn đã thử nghiệm.
Lucas

Good Effort and Research @thymine
vibs2006

1
nó được sắp xếp thành tài liệu, nếu số lượng nguồn tham chiếu. mailmessage.dispose gọi các tệp đính kèm.dispose trong đó lần lượt các lệnh gọi loại bỏ trên mỗi tệp đính kèm , trong mimepart, đóng luồng .
Cee McSharpface,

Cảm ơn bạn. Tôi đã nghĩ rằng thư phải làm điều đó và cần nó vì tôi đang tạo thư của mình ở các lớp khác với nơi thư thực sự được gửi.
xr280xr

20

Nếu bạn thực sự muốn thêm .pdf, tôi thấy cần phải đặt vị trí của luồng bộ nhớ thành Zero.

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

Dành hàng giờ để gửi một bản pdf, điều này giống như một sự quyến rũ!
dijam

12

Nếu tất cả những gì bạn đang làm là đính kèm một chuỗi, bạn có thể làm điều đó chỉ trong 2 dòng:

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

Tôi không thể làm việc bằng máy chủ thư của chúng tôi với StreamWriter.
Tôi nghĩ có lẽ vì với StreamWriter, bạn đang thiếu nhiều thông tin thuộc tính tệp và có thể máy chủ của chúng tôi không thích những gì bị thiếu.
Với Attachment.CreateAttachmentFromString (), nó đã tạo ra mọi thứ tôi cần và hoạt động tuyệt vời!

Nếu không, tôi khuyên bạn nên lấy tệp của bạn có trong bộ nhớ và mở nó bằng MemoryStream (byte []), và bỏ qua StreamWriter cùng nhau.


2

Tôi trả lời câu hỏi này vì tôi cần đính kèm tệp Excel mà tôi tạo thông qua mã và có sẵn dưới dạng MemoryStream. Tôi có thể đính kèm nó vào thư nhưng nó đã được gửi dưới dạng tệp 64Bytes thay vì ~ 6KB như ý muốn. Vì vậy, giải pháp phù hợp với tôi là:

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

Đặt giá trị attachment.ContentDisposition.Sizecho phép tôi gửi tin nhắn với kích thước chính xác của tệp đính kèm.


2

sử dụng dòng bộ nhớ MỞ KHÁC:

ví dụ cho lauch pdf và gửi pdf trong 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; là dòng đã giúp tôi. mà không có nó attcahment của tôi chỉ là 504 byte instaed của một số đài KBS
Abdul Hameed

-6

Tôi nghĩ mã này sẽ giúp bạn:

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 Câu trả lời này tải tệp đính kèm từ đĩa bằng cách sử dụng phương thức khởi tạo Attachment (string fileName). OP đặc biệt nói rằng anh ta không muốn tải từ đĩa. Ngoài ra, đây chỉ là đoạn mã được sao chép từ liên kết trong câu trả lời của Red Swan.
Walter Stabosz

Dòng tệp đính kèm cũng không được xử lý
Sameh
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.