Joindre un fichier de MemoryStream à un MailMessage en C #


113

J'écris un programme pour joindre un fichier à un e-mail. Actuellement, j'enregistre le fichier en utilisant FileStreamsur le disque, puis j'utilise

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

Je ne veux pas stocker de fichier sur le disque, je veux stocker le fichier en mémoire et à partir du flux de mémoire, passez-le à Attachment.

Réponses:


104

Voici l exemple de code.

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

Modifier 1

Vous pouvez spécifier d'autres types de fichiers par System.Net.Mime.MimeTypeNames comme System.Net.Mime.MediaTypeNames.Application.Pdf

En fonction du type Mime, vous devez spécifier l'extension correcte dans FileName par exemple"myFile.pdf"


J'utilise PDF Comment passer ce type à System.Net.Mime.ContentType ct = new System.Net.Mime.ContentType (System.Net.Mime.MediaTypeNames.Text.Plain);
Zain Ali

3
Vous devez utiliserSystem.Net.Mime.MediaTypeNames.Application.Pdf
Waqas Raja

5
writer.Disopose()était trop tôt pour ma solution mais tous les autres sont un excellent exemple.
Kazimierz Jawor

7
Je suis presque sûr qu'il devrait y avoir un ms.Position = 0;avant de créer la pièce jointe.
Kenny Evitt

94

Une entrée un peu tardive - mais j'espère toujours utile à quelqu'un là-bas: -

Voici un extrait de code simplifié pour envoyer une chaîne en mémoire sous forme de pièce jointe à un e-mail (un fichier CSV dans ce cas particulier).

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

Le StreamWriter et le flux sous-jacent ne doivent pas être supprimés tant que le message n'a pas été envoyé (à éviter ObjectDisposedException: Cannot access a closed Stream).


30
Pour tous les nouveaux arrivants, la clé pour moi était de régler lestream.position = 0;
mtbennett

3
+1 pour une utilisation appropriée de using () - quelque chose qui semble toujours manquer dans les exemples et les extraits en ligne (y compris la réponse acceptée à cette question).
Jay Querido

2
Merci à @mtbennet, c'était aussi mon problème stream.Position=0.
Icarus

Que fait la définition du type MIME ici? Quelque chose pour l'application client e-mail?
xr280xr

@ xr280xr - Correct. Ce paramètre n'est pas réellement obligatoire, mais son inclusion devrait aider le client de messagerie du destinataire à gérer la pièce jointe de manière judicieuse. docs.microsoft.com/en-us/dotnet/api/…
tranquil tarn

28

Étant donné que je n'ai trouvé aucune confirmation de cela, j'ai testé si l'élimination du MailMessage et / ou de l'objet Attachment éliminerait le flux chargé dans ces derniers comme je m'y attendais.

Il apparaît avec le test suivant que lorsque le MailMessage est supprimé, tous les flux utilisés pour créer des pièces jointes seront également supprimés. Donc, tant que vous supprimez votre MailMessage, les flux qui ont servi à sa création n'ont pas besoin d'être traités au-delà de cela.

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

Merde, c'est intelligent. Une ligne de code et vous pouvez ajouter un fichier image à un e-mail en tant que pièce jointe. Bon conseil!
Mike Gledhill

Je souhaite que cela soit réellement documenté. Votre test / vérification de ce comportement est utile, mais sans être dans la documentation officielle, il est difficile de croire que ce sera toujours le cas. Quoi qu'il en soit, merci pour les tests.
Lucas

Good Effort and Research @thymine
vibs2006

1
c'est en quelque sorte documenté, si la source de référence compte. mailmessage.dispose appelle attachments.dispose qui à son tour, les appels disposent sur chaque pièce jointe qui, dans mimepart, ferme le flux .
Cee McSharpface

Je vous remercie. Je pensais que le message électronique devrait faire cela et en avoir besoin parce que je crée mes messages dans des classes différentes de celles où le message est réellement envoyé.
xr280xr

20

Si vous souhaitez réellement ajouter un .pdf, j'ai trouvé nécessaire de définir la position du flux de mémoire sur zéro.

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

Passez des heures à envoyer un pdf, cela a fonctionné comme un charme!
dijam

12

Si vous ne faites que joindre une chaîne, vous pouvez le faire en seulement 2 lignes:

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

Je n'ai pas pu faire fonctionner le mien en utilisant notre serveur de messagerie avec StreamWriter.
Je pense que peut-être parce qu'avec StreamWriter il vous manque beaucoup d'informations sur les propriétés de fichiers et peut-être que notre serveur n'a pas aimé ce qui manquait.
Avec Attachment.CreateAttachmentFromString (), il a créé tout ce dont j'avais besoin et fonctionne très bien!

Sinon, je suggère de prendre votre fichier qui est en mémoire et de l'ouvrir à l'aide de MemoryStream (octet []), et de sauter le StreamWriter tous ensemble.


2

J'ai atterri sur cette question car j'avais besoin de joindre un fichier Excel que je génère via du code et qui est disponible en tant que MemoryStream. Je pourrais le joindre au message électronique, mais il a été envoyé sous forme de fichier de 64 octets au lieu de ~ 6 Ko comme prévu. Donc, la solution qui a fonctionné pour moi était la suivante:

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

Définition de la valeur de attachment.ContentDisposition.Sizelaissez-moi envoyer des messages avec la taille correcte de la pièce jointe.


2

utiliser AUTRE flux de mémoire OPEN:

exemple pour lancer un pdf et envoyer un pdf dans 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; est la ligne qui m'a aidé. sans cela, mon attachement ne faisait que 504 octets instaed de quelques kBs
Abdul Hameed

-6

Je pense que ce code vous aidera:

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 Cette réponse charge la pièce jointe à partir du disque à l'aide du constructeur Attachment (string fileName). L'OP déclare spécifiquement qu'il ne veut pas charger à partir du disque. De plus, ce n'est que le code copié à partir du lien dans la réponse de Red Swan.
Walter Stabosz

Le flux attachFile n'est pas supprimé également
Sameh
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.