Allega un file da MemoryStream a un MailMessage in C #


113

Sto scrivendo un programma per allegare un file a un'e-mail. Attualmente sto salvando il file utilizzando FileStreamsu disco, quindi utilizzo

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

Non voglio archiviare file su disco, voglio archiviare file in memoria e dal flusso di memoria passarlo a Attachment.

Risposte:


104

Ecco il codice di esempio.

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

Modifica 1

È possibile specificare altri tipi di file da System.Net.Mime.MimeTypeNames come System.Net.Mime.MediaTypeNames.Application.Pdf

In base al tipo Mime, è necessario specificare l'estensione corretta in FileName, ad esempio"myFile.pdf"


Sto usando PDF Come passare questo tipo a System.Net.Mime.ContentType ct = new System.Net.Mime.ContentType (System.Net.Mime.MediaTypeNames.Text.Plain);
Zain Ali

3
Devi usareSystem.Net.Mime.MediaTypeNames.Application.Pdf
Waqas Raja

5
writer.Disopose()era troppo presto per la mia soluzione ma tutto il resto è un ottimo esempio.
Kazimierz Jawor

7
Sono abbastanza sicuro che dovrebbe esserci un ms.Position = 0;prima di creare l'allegato.
Kenny Evitt

94

Un po 'in ritardo - ma si spera ancora utile a qualcuno là fuori: -

Ecco uno snippet semplificato per inviare una stringa in memoria come allegato e-mail (un file CSV in questo caso particolare).

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

Lo StreamWriter e il flusso sottostante non devono essere eliminati fino a quando il messaggio non è stato inviato (per evitare ObjectDisposedException: Cannot access a closed Stream).


30
Per tutti i nuovi arrivati, la chiave per me era impostare ilstream.position = 0;
mtbennett

3
+1 per un uso appropriato dell'uso di () - qualcosa che sembra sempre mancare negli esempi e nei frammenti online (inclusa la risposta accettata a questa domanda).
Jay Querido

2
Grazie a @mtbennet quello era anche il mio problema: l'impostazione stream.Position=0.
Icaro

Cosa fa effettivamente l'impostazione del tipo MIME qui? Qualcosa per l'app client di posta elettronica?
xr280xr

@ xr280xr - Corretto. Questo parametro non è effettivamente richiesto, ma includerlo dovrebbe aiutare il client di posta elettronica del destinatario a gestire l'allegato in modo ragionevole. docs.microsoft.com/en-us/dotnet/api/…
tarn tranquillo

28

Dal momento che non sono riuscito a trovare la conferma di ciò da nessuna parte, ho verificato se l'eliminazione di MailMessage e / o l'oggetto Allegato avrebbe eliminato lo stream caricato in essi come mi aspettavo.

Con il seguente test appare che quando MailMessage viene eliminato, verranno eliminati anche tutti i flussi utilizzati per creare allegati. Quindi, finché elimini il tuo MailMessage, i flussi che sono stati creati per crearlo non hanno bisogno di essere gestiti oltre.

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

Dannazione, è intelligente. Una riga di codice e potresti aggiungere un file immagine a un'email come allegato. Ottimo suggerimento!
Mike Gledhill

Vorrei che questo fosse effettivamente documentato. Il tuo test / verifica di questo comportamento è utile, ma senza essere nella documentazione ufficiale è difficile credere che sarà sempre così. Comunque, grazie per i test.
Lucas

Good Effort and Research @thymine
vibs2006

1
è una specie di documentato, se la fonte di riferimento conta. mailmessage.dispose chiama attachments.dispose che a sua volta le chiamate dispose su ogni allegato che, a mimepart, chiude lo stream .
Cee McSharpface

Grazie. Stavo pensando che il messaggio di posta dovrebbe farlo e ne ha bisogno perché sto creando i miei messaggi in classi diverse da quelle in cui il messaggio viene effettivamente inviato.
xr280xr

20

Se in realtà vuoi aggiungere un .pdf, ho ritenuto necessario impostare la posizione del flusso di memoria su 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);

Passa ore a inviare un pdf, questo ha funzionato alla grande!
dijam

12

Se tutto ciò che stai facendo è allegare una stringa, potresti farlo in sole 2 righe:

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

Non sono riuscito a far funzionare il mio utilizzando il nostro server di posta con StreamWriter.
Penso che forse perché con StreamWriter ti mancano molte informazioni sulle proprietà dei file e forse al nostro server non è piaciuto ciò che mancava.
Con Attachment.CreateAttachmentFromString () ha creato tutto ciò di cui avevo bisogno e funziona alla grande!

Altrimenti, suggerirei di prendere il file che è in memoria e di aprirlo utilizzando MemoryStream (byte []) e di saltare lo StreamWriter tutti insieme.


2

Sono arrivato a questa domanda perché avevo bisogno di allegare un file Excel generato tramite codice ed è disponibile come MemoryStream. Potrei allegarlo al messaggio di posta, ma è stato inviato come file da 64Bytes invece di ~ 6KB come previsto. Quindi, la soluzione che ha funzionato per me è stata questa:

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

Impostazione del valore di attachment.ContentDisposition.Sizeconsentimi di inviare messaggi con la dimensione corretta dell'allegato.


2

usa ALTRO flusso di memoria APERTO:

esempio per lanciare pdf e inviare pdf in 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; è la linea che mi ha aiutato. senza di essa il mio attacco era di soli 504 byte con l'inserimento di alcuni kB
Abdul Hameed

-6

Penso che questo codice ti aiuterà:

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 Questa risposta carica l'allegato dal disco utilizzando il costruttore Attachment (string fileName). L'OP afferma specificamente che non vuole caricare dal disco. Inoltre, questo è solo il codice copiato dal link nella risposta di Red Swan.
Walter Stabosz

Anche il flusso di attachFile non viene eliminato
Sameh
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.