Hängen Sie eine Datei aus MemoryStream an eine MailMessage in C # an


113

Ich schreibe ein Programm, um eine Datei an eine E-Mail anzuhängen. Derzeit speichere ich Datei mit FileStreamauf Festplatte, und dann verwende ich

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

Ich möchte keine Datei auf der Festplatte speichern, ich möchte eine Datei im Speicher speichern und diese vom Speicherstrom an weiterleiten Attachment.

Antworten:


104

Hier ist der Beispielcode.

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

Bearbeiten 1

Sie können andere Dateitypen über System.Net.Mime.MimeTypeNames wie angeben System.Net.Mime.MediaTypeNames.Application.Pdf

Basierend auf dem MIME-Typ müssen Sie beispielsweise in FileName die richtige Erweiterung angeben"myFile.pdf"


Ich verwende PDF So übergeben Sie diesen Typ an System.Net.Mime.ContentType ct = new System.Net.Mime.ContentType (System.Net.Mime.MediaTypeNames.Text.Plain);
Zain Ali

3
Sie müssen verwendenSystem.Net.Mime.MediaTypeNames.Application.Pdf
Waqas Raja

5
writer.Disopose()war zu früh für meine Lösung, aber alles andere ist ein gutes Beispiel.
Kazimierz Jawor

7
Ich bin mir ziemlich sicher, dass es ms.Position = 0;vor dem Erstellen des Anhangs einen geben sollte.
Kenny Evitt

94

Ein bisschen verspäteter Eintrag - aber hoffentlich immer noch nützlich für jemanden da draußen: -

Hier ist ein vereinfachtes Snippet zum Senden einer speicherinternen Zeichenfolge als E-Mail-Anhang (in diesem speziellen Fall eine CSV-Datei).

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

Der StreamWriter und der zugrunde liegende Stream sollten erst nach dem Senden der Nachricht entsorgt werden (um dies zu vermeiden ObjectDisposedException: Cannot access a closed Stream).


30
Für alle Neulinge war der Schlüssel für mich, dasstream.position = 0;
mtbennett

3
+1 für die angemessene Verwendung von using () - etwas, das in Beispielen und Snippets online immer zu fehlen scheint (einschließlich der akzeptierten Antwort auf diese Frage).
Jay Querido

2
Dank @mtbennet war das auch meine Problemstellung stream.Position=0.
Ikarus

Was macht das Einstellen des MIME-Typs hier eigentlich? Etwas für die E-Mail-Client-App?
xr280xr

@ xr280xr - Richtig. Dieser Parameter ist eigentlich nicht erforderlich, sollte jedoch dem E-Mail-Client des Empfängers helfen, den Anhang sinnvoll zu handhaben. docs.microsoft.com/en-us/dotnet/api/…
ruhiger Tarn

28

Da ich nirgendwo eine Bestätigung dafür finden konnte, habe ich getestet, ob das Entsorgen der MailMessage und / oder des Attachment-Objekts den in sie geladenen Stream wie erwartet entsorgen würde.

Beim folgenden Test wird angezeigt, dass beim Entsorgen der MailMessage alle zum Erstellen von Anhängen verwendeten Streams ebenfalls entsorgt werden. Solange Sie Ihre MailMessage entsorgen, müssen die Streams, mit denen sie erstellt wurden, nicht darüber hinaus verarbeitet werden.

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

Verdammt, das ist klug. Eine Codezeile, und Sie können einer E-Mail eine Bilddatei als Anhang hinzufügen. Toller Tipp!
Mike Gledhill

Ich wünschte, dies wäre tatsächlich dokumentiert. Ihr Test / Ihre Überprüfung dieses Verhaltens ist nützlich, aber ohne in der offiziellen Dokumentation zu stehen, ist es schwierig zu vertrauen, dass dies immer der Fall sein wird. Trotzdem danke fürs Testen.
Lucas

Gute Anstrengung und Forschung @thymine
vibs2006

1
Es ist irgendwie dokumentiert, wenn die Referenzquelle zählt. mailmessage.dispose ruft attachments.dispose auf, die wiederum Aufrufe für jeden Anhang bereitstellen, der in mimepart den Stream schließt .
Cee McSharpface

Danke dir. Ich dachte, dass die E-Mail-Nachricht das tun sollte und muss, weil ich meine Nachrichten in anderen Klassen erstelle, als dort, wo die Nachricht tatsächlich gesendet wird.
xr280xr

20

Wenn Sie tatsächlich eine PDF-Datei hinzufügen möchten, musste die Position des Speicherstroms auf Null gesetzt werden.

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

Verbringen Sie Stunden damit, ein PDF zu senden. Das hat wie ein Zauber gewirkt!
Dijam

12

Wenn Sie nur eine Zeichenfolge anhängen, können Sie dies in nur zwei Zeilen tun:

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

Ich konnte meine mit StreamWriter nicht über unseren Mailserver zum Laufen bringen.
Ich denke, vielleicht, weil Sie mit StreamWriter viele Informationen zu Dateieigenschaften vermissen und unser Server vielleicht nicht mochte, was fehlte.
Mit Attachment.CreateAttachmentFromString () wurde alles erstellt, was ich brauchte, und es funktioniert großartig!

Andernfalls würde ich vorschlagen, Ihre im Speicher befindliche Datei mit MemoryStream (Byte []) zu öffnen und den StreamWriter insgesamt zu überspringen.


2

Ich bin auf diese Frage gestoßen, weil ich eine Excel-Datei anhängen musste, die ich über Code generiere und die als verfügbar ist MemoryStream. Ich konnte es an die E-Mail-Nachricht anhängen, aber es wurde als 64-Byte-Datei anstelle von ~ 6 KB gesendet, wie es gemeint war. Die Lösung, die für mich funktioniert hat, war folgende:

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

Festlegen des Werts von attachment.ContentDisposition.SizeLassen Sie mich Nachrichten mit der richtigen Größe des Anhangs senden.


2

Verwenden Sie ANDEREN OFFENEN Memorystream:

Beispiel für lauch pdf und pdf in MVC4 C # Controller senden

        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; ist die Linie, die mir geholfen hat. ohne sie war meine attcahment nur 504 Bytes von einigen kBs instaed
Abdul Hameed

-6

Ich denke, dieser Code wird Ihnen helfen:

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 Diese Antwort lädt den Anhang mithilfe des Konstruktors Anhang (Zeichenfolge Dateiname) von der Festplatte. Das OP gibt ausdrücklich an, dass er nicht von der Festplatte laden möchte. Dies ist auch nur der Code, der aus dem Link in Red Swans Antwort kopiert wurde.
Walter Stabosz

attachFile Stream wird auch nicht entsorgt
Sameh
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.