MemoryStream'den bir MailMessage'a C # 'da bir dosya ekleyin


113

E-postaya dosya eklemek için bir program yazıyorum. Şu anda kullanarak dosyayı FileStreamdiske kaydediyorum ve sonra kullanıyorum

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

Dosyayı diskte depolamak istemiyorum, dosyayı bellekte depolamak istiyorum ve bellek akışından bunu Attachment.

Yanıtlar:


104

İşte örnek kod.

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

Düzenle 1

System.Net.Mime.MimeTypeNames ile diğer dosya türlerini belirtebilirsiniz. System.Net.Mime.MediaTypeNames.Application.Pdf

Dayanarak Mim Tipi Eğer örneğin DosyaAdı doğru uzantısı belirtmek gerekir"myFile.pdf"


PDF kullanıyorum Bu tür System.Net.Mime.ContentType'a nasıl iletilir ct = new System.Net.Mime.ContentType (System.Net.Mime.MediaTypeNames.Text.Plain);
Zain Ali

3
Kullanmanız gerekenSystem.Net.Mime.MediaTypeNames.Application.Pdf
Waqas Raja

5
writer.Disopose()benim çözümüm için çok erkendi ama diğerleri harika bir örnek.
Kazimierz Jawor

7
ms.Position = 0;Eki oluşturmadan önce bir tane olması gerektiğinden oldukça eminim .
Kenny Evitt

94

Biraz geç bir giriş - ama umarım dışarıdaki biri için hala yararlıdır: -

E-posta eki (bu özel durumda bir CSV dosyası) olarak bellek içi bir dize göndermek için basitleştirilmiş bir kod parçacığı burada verilmiştir.

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 ve temel alınan akış, mesaj gönderildikten sonra (önlemek için ObjectDisposedException: Cannot access a closed Stream) elden çıkarılmamalıdır .


30
Yeni gelenler için anahtar benim içinstream.position = 0;
mtbennett

3
() 'Nin uygun kullanımı için +1 - çevrimiçi örneklerde ve pasajlarda her zaman eksik görünen bir şey (bu sorunun kabul edilen yanıtı dahil).
Jay Querido

2
@Mtbennet sayesinde o da benim sorunumdu - ayar stream.Position=0.
Icarus

MIME türünü ayarlamak burada gerçekte ne işe yarar? E-posta istemcisi uygulaması için bir şey?
xr280xr

@ xr280xr - Doğru. Bu parametre aslında gerekli değildir, ancak dahil edilmesi, alıcının e-posta istemcisinin eki mantıklı bir şekilde işlemesine yardımcı olmalıdır. docs.microsoft.com/en-us/dotnet/api/…
sakin tarn

28

Bunun onayını hiçbir yerde bulamadığım için MailMessage ve / veya Attachment nesnesinin atılmasının onlara yüklenen akışı beklediğim gibi atıp atmayacağını test ettim.

Aşağıdaki testle, MailMessage atıldığında, ekler oluşturmak için kullanılan tüm akışların da atılacağı görülmektedir. MailMessage'ınızı elden çıkardığınız sürece, onu oluşturmaya giden akışların bunun ötesinde işlem yapması gerekmez.

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

Kahretsin, bu akıllıca. Bir kod satırı ve bir e-postaya ek olarak bir resim dosyası ekleyebilirsiniz. Harika bir ipucu!
Mike Gledhill

Bunun gerçekten belgelenmesini dilerdim. Bu davranışı test etmeniz / doğrulamanız yararlıdır, ancak resmi belgeler olmadan bunun her zaman böyle olacağına güvenmek zordur. Her neyse, test ettiğiniz için teşekkürler.
Lucas

İyi Çaba ve Araştırma @thymine
vibs2006

1
referans kaynağı sayılırsa, bir tür belgelendirilir. mailmessage.dispose çağrıları attachments.dispose , sırayla çağrıların mimepart'ta akışı kapatan her eke atılmasını sağlar .
Cee McSharpface

Teşekkür ederim. Posta mesajının bunu yapması gerektiğini ve buna ihtiyacı olduğunu düşünüyordum çünkü mesajlarımı mesajın gerçekte gönderildiği yerden farklı sınıflarda oluşturuyorum.
xr280xr

20

Aslında bir .pdf eklemek istiyorsanız, bellek akışının konumunu Sıfır olarak ayarlamayı gerekli buldum.

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

Bir pdf göndermek için saatler harcayın, bu harika çalıştı!
dijam

12

Tek yaptığınız bir dizge eklemekse, bunu sadece 2 satırda yapabilirsiniz:

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

StreamWriter ile posta sunucumuzu kullanarak benimkini çalıştıramadım.
Sanırım belki StreamWriter ile çok sayıda dosya özelliği bilgisini kaçırdığınız ve belki de sunucumuz eksik olanı beğenmediği içindir.
Attachment.CreateAttachmentFromString () ile ihtiyacım olan her şeyi yarattı ve harika çalışıyor!

Aksi takdirde, hafızadaki dosyanızı alıp MemoryStream (bayt []) kullanarak açmanızı ve StreamWriter'ı hep birlikte atlamanızı öneririm.


2

Bu soruya geldim çünkü kod aracılığıyla oluşturduğum ve olarak mevcut olan bir Excel dosyasını eklemem gerekiyor MemoryStream. Bunu posta mesajına ekleyebilirdim ama kastedildiği gibi ~ 6KB yerine 64Bytes dosyası olarak gönderildi. Yani benim için işe yarayan çözüm şuydu:

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.SizeDoğru boyutta ek ile mesaj göndermeme izin ver değerini ayarlama .


2

DİĞER AÇIK bellek akışını kullanın:

lauch pdf için örnek ve MVC4 C # Controller'da pdf gönderin

        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; bana yardımcı olan çizgi. onsuz benim atamam bazı KB'lardan sadece 504 bayttı
Abdul Hameed

-6

Bu kodun size yardımcı olacağını düşünüyorum:

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 Bu yanıt, Attachment (string fileName) yapıcısını kullanarak eki diskten yükler. OP, özellikle diskten yüklemek istemediğini belirtir. Ayrıca bu, Red Swan'ın cevabındaki bağlantıdan kopyalanıp yapıştırılan koddur.
Walter Stabosz

attachFile akışı da elden çıkarılmaz
Sameh
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.