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.