Attach a File from Memorystream to a Mailmessage in C#

Attach a file from MemoryStream to a MailMessage in 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"

Creating MailMessage Attachment from MemoryStream

Played around with this code snippet in a unit test project and I couldn't get the ContentDisposition property to change from -1.

Did however get the MemoryStream populated with data, and switching between memStream.Position = 0 to memStream.Seek(0, SeekOrigin.Begin); didn't seem to help.

I did notice that the memStream.Close was clearing out the Attachment.ContentStream property.

Try sending the message before closing the memory stream where the attachment data is stored.

Email Attachment from memory stream is coming as blank in C#

I think the attachment is confusing the mail system. Microsoft's recommendation is to specify the content type as an octet. Below is a replacement for initializing the attachment. The reset of your code looks fine.

string filename = "Input" + DateTime.Now.ToString("yyyyMMdd_hhss") + ".xls";
attachment = new System.Net.Mail.Attachment(memoryStream, filename, MediaTypeNames.Application.Octet);

C# - Attach FileStream in Sending to Email System.ObjectDisposedException

Your code

using (var fs = new FileStream("Filename.txt", FileMode.Create))
{
ms.CopyTo(fs);
return fs; // you are returning here
} // hang on, this is a using statement which will dispose fs!

Will translate to this

FileStream fileStream = new FileStream("Filename.txt", FileMode.Create);
try
{
return fileStream;
}
finally
{
if (fileStream != null)
{
((IDisposable)fileStream).Dispose();
}
}

It's important to note, that if you return in a try finally, it stores the return value in a local variable, to return after the finally. Which will look something like this

FileStream fileStream = new FileStream("Filename.txt", FileMode.Create);
try
{
temp = fileStream;
}
finally
{
if (fileStream != null)
{
((IDisposable)fileStream).Dispose();
}
}

return temp;

We can take a look at the IL to see what's happening

IL_0000: ldstr "someFile"
IL_0005: ldc.i4.2
IL_0006: newobj instance void [mscorlib]System.IO.FileStream::.ctor(string, valuetype[mscorlib]System.IO.FileMode)
// stloc.0 Pops the current value from the top of the evaluation stack and stores it in the
// local variable list at a specified index. This is your fs reference
IL_000b: stloc.0
.try
{
// ldloc.0 Loads the local variable at a specific index onto the evaluation stack.
// This is your fs reference
IL_000c: ldloc.0
// stloc.1 Pops the current value from the top of the evaluation stack and stores it in
// the local variable list at a specified index. This is your fs reference
IL_000d: stloc.1
IL_000e: leave.s IL_001a
} // end .try
finally
{
IL_0010: ldloc.0
IL_0011: brfalse.s IL_0019
IL_0013: ldloc.0
// oh no we just Disposed fs!!!
IL_0014: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_0019: endfinally
} // end handler

// ldloc.1 Loads the local variable at a specific index onto the evaluation stack.
// This is your fs reference
IL_001a: ldloc.1
//ret Returns from the current method, pushing a return value (if present) from
//the callee's evaluation stack onto the caller's evaluation stack.
IL_001b: ret

In short, don't return an IDisposable reference from a using statement as it will get disposed.

You will need to create the FileStream (without the using) and Dispose it in another context, or refactor your code.

Update

But my email sending doesn't work after I put a using statement
covering the sending of email with stream

You maybe over-complicating this, try something like this

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("file content blah blah blahh");
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);
}

How to put an image file into a MemoryStream and attach it into an Email


using (MailMessage Message = new MailMessage())
{
Message.From = new MailAddress("from@mail.com");
Message.Subject = "My Subject";
Message.Body = "My Body";
Message.To.Add(new MailAddress("to@mail.com"));

//Attach more file
foreach (var item in Attachment)
{
MemoryStream ms = new MemoryStream(File.ReadAllBytes(filePath));

Attachment Data = new Attachment(ms, "FileName");
ContentDisposition Disposition = Data.ContentDisposition;
Disposition.CreationDate = DateTime.UtcNow.AddHours(-5);
Disposition.ModificationDate = DateTime.UtcNow.AddHours(-5);
Disposition.ReadDate = DateTime.UtcNow.AddHours(-5);
Data.ContentType = new ContentType(MediaTypeNames.Application.Pdf);
Message.Attachments.Add(Data);
}

SmtpClient smtp = new SmtpClient("SmtpAddress", "SmtpPort");
smtp.Credentials = new NetworkCredential("SmtpUser", "SmtpPassword");
await smtp.SendMailAsync(Message);
}

I hope this helps

How to attach .docx and .doc files to the email from memory stream?

You should use MediaTypeNames.Application.Octet as mime type.

From : https://docs.microsoft.com/fr-fr/dotnet/api/system.net.mime.mediatypenames.application.octet?view=netframework-4.7.2

Send MailKit email with an attachment from memoryStream

If you'd like to stick with the MimeKit's BodyBuilder to build your message body, you can do something like this:

var emailBody = new MimeKit.BodyBuilder
{
HtmlBody = htmlString
};
emailBody.Attachments.Add ("Receipt.pdf", bytes);

// If you find that MimeKit does not properly auto-detect the mime-type based on the
// filename, you can specify a mime-type like this:
//emailBody.Attachments.Add ("Receipt.pdf", bytes, ContentType.Parse (MediaTypeNames.Application.Pdf));

message.Body = emailBody.ToMessageBody ();


Related Topics



Leave a reply



Submit