Attach a file from MemoryStream to a MailMessage in C#

C#EmailSmtpMemorystream

C# Problem Overview


I am writing a program to attach a file to email. Currently I am saving file using FileStream into disk, and then I use

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

I do not want to store file in disk, I want to store file in memory and from memory stream pass this to Attachment.

C# Solutions


Solution 1 - C#

Here is the sample 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();

Edit 1

You can specify other file types by System.Net.Mime.MimeTypeNames like System.Net.Mime.MediaTypeNames.Application.Pdf

Based on Mime Type you need to specify correct extension in FileName for instance "myFile.pdf"

Solution 2 - C#

A bit of a late entry - but hopefully still useful to someone out there:-

Here's a simplified snippet for sending an in-memory string as an email attachment (a CSV file in this particular case).

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("[email protected]", "[email protected]", "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);
}

The StreamWriter and underlying stream should not be disposed until after the message has been sent (to avoid ObjectDisposedException: Cannot access a closed Stream).

Solution 3 - C#

Since I couldn't find confirmation of this anywhere, I tested if disposing of the MailMessage and/or the Attachment object would dispose of the stream loaded into them as I expected would happen.

It does appear with the following test that when the MailMessage is disposed, all streams used to create attachments will also be disposed. So as long as you dispose your MailMessage the streams that went into creating it do not need handling beyond that.

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

Solution 4 - C#

If you actually want to add a .pdf, I found it necessary to set the position of the memory stream to 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);

Solution 5 - C#

If all you're doing is attaching a string, you could do it in just 2 lines:

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

I wasn't able to get mine to work using our mail server with StreamWriter.
I think maybe because with StreamWriter you're missing a lot of file property information and maybe our server didn't like what was missing.
With Attachment.CreateAttachmentFromString() it created everything I needed and works great!

Otherwise, I'd suggest taking your file that is in memory and opening it using MemoryStream(byte[]), and skipping the StreamWriter all together.

Solution 6 - C#

I landed on this question because I needed to attach an Excel file I generate through code and is available as MemoryStream. I could attach it to the mail message but it was sent as 64Bytes file instead of a ~6KB as it was meant. So, the solution that worked for me was this:

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

Setting the value of attachment.ContentDisposition.Size let me send messages with the correct size of attachment.

Solution 7 - C#

use OTHER OPEN memorystream:

example for lauch pdf and send 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);
    }

Solution 8 - C#

I think this code will help you:

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionZain AliView Question on Stackoverflow
Solution 1 - C#Waqas RajaView Answer on Stackoverflow
Solution 2 - C#tranquil tarnView Answer on Stackoverflow
Solution 3 - C#ThymineView Answer on Stackoverflow
Solution 4 - C#Jason DimmickView Answer on Stackoverflow
Solution 5 - C#MikeTeeVeeView Answer on Stackoverflow
Solution 6 - C#ilFornaView Answer on Stackoverflow
Solution 7 - C#Ángel IbáñezView Answer on Stackoverflow
Solution 8 - C#r12View Answer on Stackoverflow