Lampirkan file dari MemoryStream ke MailMessage di C #

113

Saya sedang menulis program untuk melampirkan file ke email. Saat ini saya menyimpan file menggunakan FileStreamke disk, dan kemudian saya gunakan

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

Saya tidak ingin menyimpan file di disk, saya ingin menyimpan file di memori dan dari aliran memori meneruskan ini ke Attachment.

Zain Ali
sumber

Jawaban:

104

Ini contoh kode.

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

Edit 1

Anda dapat menentukan jenis file lain dengan System.Net.Mime.MimeTypeNames seperti System.Net.Mime.MediaTypeNames.Application.Pdf

Berdasarkan Jenis Mime Anda perlu menentukan ekstensi yang benar di FileName misalnya"myFile.pdf"

Waqas Raja
sumber
Saya menggunakan PDF Cara meneruskan jenis ini ke System.Net.Mime.ContentType ct = new System.Net.Mime.ContentType (System.Net.Mime.MediaTypeNames.Text.Plain);
Zain Ali
3
Anda perlu menggunakanSystem.Net.Mime.MediaTypeNames.Application.Pdf
Waqas Raja
5
writer.Disopose()terlalu dini untuk solusi saya tetapi yang lainnya adalah contoh yang bagus.
Kazimierz Jawor
7
Saya cukup yakin harus ada ms.Position = 0;sebelum membuat lampiran.
Kenny Evitt
94

Agak terlambat masuk - tapi semoga masih bermanfaat bagi seseorang di luar sana: -

Berikut cuplikan yang disederhanakan untuk mengirim string dalam memori sebagai lampiran email (file CSV dalam kasus khusus ini).

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("[email protected]", "[email protected]", "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 dan aliran yang mendasarinya tidak boleh dibuang hingga pesan telah dikirim (untuk menghindari ObjectDisposedException: Cannot access a closed Stream).

tarn tenang
sumber
30
Untuk setiap pendatang baru, kuncinya bagi saya adalah menyetelstream.position = 0;
mtbennett
3
+1 untuk penggunaan yang tepat dari using () - sesuatu yang sepertinya selalu hilang dari contoh dan cuplikan online (termasuk jawaban yang diterima untuk pertanyaan ini).
Jay Querido
2
Terima kasih kepada @mtbennet itu juga masalah saya - pengaturan stream.Position=0.
Icarus
Apa sebenarnya pengaturan tipe MIME di sini? Sesuatu untuk aplikasi klien email?
xr280xr
@ xr280xr - Benar. Parameter ini sebenarnya tidak diperlukan, tetapi menyertakannya akan membantu klien email penerima menangani lampiran dengan bijaksana. docs.microsoft.com/en-us/dotnet/api/…
tenang tarn
28

Karena saya tidak dapat menemukan konfirmasi ini di mana pun, saya menguji apakah membuang MailMessage dan / atau objek Lampiran akan membuang aliran yang dimuat ke dalamnya seperti yang saya harapkan akan terjadi.

Itu muncul dengan pengujian berikut bahwa ketika MailMessage dibuang, semua aliran yang digunakan untuk membuat lampiran juga akan dibuang. Jadi selama Anda membuang MailMessage Anda, aliran yang digunakan untuk membuatnya tidak perlu penanganan lebih dari itu.

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);
Timin
sumber
Sial, itu pintar. Satu baris kode, dan Anda dapat menambahkan file gambar ke email sebagai lampiran. Tip bagus!
Mike Gledhill
Saya berharap ini benar-benar didokumentasikan. Pengujian / verifikasi Anda atas perilaku ini berguna, tetapi tanpa ada dalam dokumentasi resmi, sulit dipercaya bahwa hal ini akan selalu terjadi. Pokoknya, terima kasih sudah mengujinya.
Lucas
Usaha dan Penelitian yang Baik @thymine
vibs2006
1
itu semacam didokumentasikan, jika jumlah sumber referensi. mailmessage.dispose memanggil attachment.dispose yang secara bergantian membuang panggilan pada setiap lampiran yang, dalam mimepart, menutup aliran .
Cee McSharpface
Terima kasih. Saya berpikir bahwa pesan email harus melakukan itu dan memerlukannya karena saya membuat pesan saya di kelas yang berbeda dari tempat pesan sebenarnya dikirim.
xr280xr
20

Jika Anda benar-benar ingin menambahkan .pdf, saya merasa perlu untuk mengatur posisi aliran memori ke Nol.

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);
Jason Dimmick
sumber
Habiskan waktu berjam-jam untuk mengirim pdf ini bekerja seperti pesona!
dijam
12

Jika yang Anda lakukan hanyalah memasang string, Anda dapat melakukannya hanya dalam 2 baris:

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

Saya tidak bisa menjalankan milik saya menggunakan server email kami dengan StreamWriter.
Saya pikir mungkin karena dengan StreamWriter Anda kehilangan banyak informasi properti file dan mungkin server kami tidak menyukai apa yang hilang.
Dengan Attachment.CreateAttachmentFromString () itu menciptakan semua yang saya butuhkan dan bekerja dengan baik!

Jika tidak, saya sarankan untuk mengambil file Anda yang ada di memori dan membukanya menggunakan MemoryStream (byte []), dan melewatkan StreamWriter secara bersamaan.

MikeTeeVee
sumber
2

Saya mendapatkan pertanyaan ini karena saya perlu melampirkan file Excel yang saya buat melalui kode dan tersedia sebagai MemoryStream. Saya dapat melampirkannya ke pesan email tetapi dikirim sebagai file 64Bytes alih-alih ~ 6KB seperti yang dimaksudkan. Jadi, solusi yang berhasil untuk saya adalah ini:

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

Mengatur nilai attachment.ContentDisposition.Sizeizinkan saya mengirim pesan dengan ukuran lampiran yang benar.

ilForna
sumber
2

gunakan aliran memori TERBUKA LAINNYA:

contoh untuk lauch pdf dan kirim pdf ke 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);
    }
Ángel Ibáñez
sumber
stream.Position=0; adalah garis yang membantu saya. tanpanya attcahment saya hanya 504 byte yang dipasang dari beberapa KB
Abdul Hameed
-6

Saya pikir kode ini akan membantu Anda:

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();
    }
  }
}
r12
sumber
5
-1 Jawaban ini memuat lampiran dari disk menggunakan konstruktor Attachment (string fileName). OP secara khusus menyatakan dia tidak ingin memuat dari disk. Juga, ini hanyalah kode yang disalin-tempel dari tautan di jawaban Red Swan.
Walter Stabosz
AttachFile stream tidak dibuang juga
Sameh