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
Accessing UI (Main) Thread Safely in Wpf
Multiple Httppost Method in Web API Controller
Using Global Keyboard Hook (Wh_Keyboard_Ll) in Wpf/C#
Add Data Annotations to a Class Generated by Entity Framework
How to Get the Calling Method Name and Type Using Reflection
How to Get the Exif Data from a File Using C#
Most Efficient Way to Remove Special Characters from String
View/Edit Id3 Data for Mp3 Files
Is There a .Net/C# Wrapper for SQLite
How to Set Aspnetcore_Environment to Be Considered for Publishing an ASP.NET Core Application
What Is the Best Data Type to Use for Money in C#
Shorter Syntax for Casting from a List<X> to a List<Y>
Using Filesystemwatcher to Monitor a Directory
Why Should I Prefer Single 'Await Task.Whenall' Over Multiple Awaits