delete attachment file - c#

i am using System.Net.Mail for sending mail in asp.net..
how to delete attachment file after it is send as attachment mail..
i tried to use File.Delete method.. but i am getting this error..
the process cannot access the file path\fun.jpg' because it is being used by another process.
thank you

Dispose of the MailMessage when you're done with it.
It still has a lock on the file you've added as an attachment until you've done so.
var filePath = "C:\\path\\to\\file.txt";
var smtpClient = new SmtpClient("mailhost");
using (var message = new MailMessage())
{
message.To.Add("to#domain.com");
message.From = new MailAddress("from#domain.com");
message.Subject = "Test";
message.SubjectEncoding = Encoding.UTF8;
message.Body = "Test " + DateTime.Now;
message.Attachments.Add(new Attachment(filePath));
}
if (File.Exists(filePath)) File.Delete(filePath);
Console.WriteLine(File.Exists(filePath));
Output: False
I would imagine that if you still have something locking the file after disposing the message, that you likely have another lock on the file, but without code, we can't help you.

You can't delete a attached file after sending the mail.Before sending you can delete.
What the error says that, the path you have mentioned is using some other process.
MailMessage Message = new MailMessage();
Message.Subject = "Attachment Test";
Message.Body = "Check out the attachment!";
Message.To.Add("webmaster#15Seconds.com");
Message.From = "someone#somedomain.com";
Message.Attachments.Add(new Attachment(memorystream, "test.txt", MediaTypeNames.Application.Text));
Notice that we created the attachment from the MemoryStream and we got to name the attachment anything we want. The name of the attachment in the second parameter is the name of the file in the email, not the name on the local system hard drive. In fact the attachment never goes to the local hard drive. The third parameter is the Mime type of the attachment, in our case this is text.
Edit: use Dispose() the mail

Extending the MailMessage class is a good way to solve this and reduce the chances of running into this problem again...
class MyMailMessage : MailMessage, IDisposable
{
private List<string> _tempFiles = new List<string>();
public void Attach(string filename)
{
base.Attachments.Add(new Attachment(filename));
this._tempFiles.add(filename);
}
new public void Dispose()
{
base.Dispose();
this._tempFiles.Foreach(x => File.Delete(x));
}
}
... and remember to use with a 'using' construct (which you should be using anyway)...
using(SmtpClient client = GetMySmtpClient())
using(MyMailMessage msd = new MyMailMessage())
{
msg.Attach(filename);
client.send(msg);
}

If your mail have lots Attachments
List<Attachments> lstAtt = new List<Attachments>();
Attachment att = new Attachment(file);
lstAtt.Add(att);
//finally
foreach(var a in lstAtt)
{
a.Dispose();
}
//delete file

You just need to dispose the message object before deleting the file. E.g:
Dim message As New MailMessage
message.From = New MailAddress(fromEmail, fromName)
message.Subject = subject
message.CC.Add(toCCEmail)
message.Bcc.Add(toBCCEmail)
Dim attach As Attachment = New Attachment(attachmentPath)
message.Attachments.Add(attach)
message.IsBodyHtml = True
message.Body = body
mailClient.Send(message)
message.Dispose() 'Add this line to dispose the message!

Related

Cannot access a closed Stream when trying to send an email using MemoryStream in ASP.NET MVC 5

I am trying to send an email with an attachment by accessing it directly after saving it in the database. To do so I am following this tutorial.
What works?
Storing the attachments in the database is correct as when I go to the details page I can see the image associated with the profile.
What doesn't?
Unfortunately there seems to be a problem with how retrieving files from database works as the attachments are damaged, e.g. image stored in database shows 153328 B, but when sent turns into 117B).
The solution that actually succeeds and sends an email (damaged email) is taken from this link, but when I try to send it using the commented out stream code, the code crashes on the indicated line:
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing); //this line
}
this is the controller code i use to save and retrieve the attachments:
public async Task<ActionResult> Create([Bind(Include = "ID,LastName,FirstMidName")] Person person, HttpPostedFileBase upload)
{
if (ModelState.IsValid)
{
if (upload != null && upload.ContentLength > 0)
{
var avatar = new File
{
FileName = System.IO.Path.GetFileName(upload.FileName),
FileType = FileType.Avatar,
ContentType = upload.ContentType
};
using (var reader = new System.IO.BinaryReader(upload.InputStream))
{
avatar.Content = reader.ReadBytes(upload.ContentLength);
}
person.Files = new List<File> { avatar };
}
db.People.Add(person);
db.SaveChanges();
//await SendEmail(person.ID);
var message = new MailMessage();
var file = db.Files.Find(person.ID);
Attachment attachment;
var stream = new MemoryStream();
try
{
stream.Write(file.Content, 0, file.Content.Length - 1);
attachment = new Attachment(stream, file.FileName);
}
catch
{
stream.Dispose();
throw;
}
//When i use this bit of code, I receive an error "Cannot access a closed stream
//using (var stream = new MemoryStream())
//{
// stream.Write(file.Content, 0, file.Content.Length - 1);
// attachment = new Attachment(stream, file.FileName);
//}
var fileSize = file.Content.Length;
message.Attachments.Add(attachment);
message.To.Add(new MailAddress("recipient#gmail.com")); // replace with valid value
message.From = new MailAddress("sender#outlook.com"); // replace with valid value
message.Subject = "Your email subject";
message.BodyEncoding = System.Text.Encoding.UTF8;
message.Body = "<p>file size: </p>" + "<p>" + fileSize + "</p>";
message.IsBodyHtml = true;
message.BodyEncoding = System.Text.Encoding.UTF8;
using (var smtp = new SmtpClient())
{
//when i try to send the mail asynchronously the view with the form just keeps showing "waiting for localhost"
//await smtp.SendMailAsync(message);
smtp.Send(message);
return RedirectToAction("Index");
}
}
return View(person);
}
Additional Question
Would it be a good idea to send the attachment inside of the save to database part?
EDIT
I have just tried sending the attachment with the below line of code:
message.Attachments.Add(new Attachment(upload.InputStream, Path.GetFileName(upload.FileName)));
added after:
person.Files = new List<File> { avatar };
But still receive damaged attachment..
EDIT 2:
I think this line
var file = db.Files.Find(person.ID)
should actually be (you were trying to get a file using a person id):
var file = db.Files.Find(avatar.ID)
but, in your case you don't need to retrieve it from the database. You already have the bytes there, so just wrap them in a MemoryStream, as you can't directly send the upload.InputStream without storing it in memory:
attachment = new Attachment(new MemoryStream(avatar.Content), file.FileName);
Looking at this quickly, I'd look at the obvious.
var file = db.Files.Find(person.ID);
Look at what this is returning. It may well be that after this object is being used, depending on what object it is, may have been disposed of already.
The reason being is you're attempting to read from the file.Content.Length which may be the very cause to the problem because it doesn't have a value or whatever.
Step through the logic, line by line. Break it down from the most simple, and build it up slowly until you get to the cause. Also, think about abstracting the logic from the controller and implementing a service that deals with this action. Check out repository pattern, unit of work and dependency injection as a side note.
Ultimately, your issue, I think it's just the fact that you're not checking all the "what if it wasn't the way you expected" type errors, which in all is why you should most probably also have some tests in place. :P
Deconstruct, start from basics and build your way up. Doing this, I'm sure you will find the problem. :)

How to save file in a folder in windows application

I want to send an attachment in an email, SO for that I want to save the attachment file in a folder first.
So what's happening with my current code is, the mail is going with attachment but my file is not getting saved into the ATTACHMENT folder.
here is the code i tried
for (int i = 0; i < table.Rows.Count; i++)
{
if (1 == 1)
{
string StrPriBody = "This is a test mail for checking notification.";
MailMessage mail = new MailMessage();
mail.Subject = "Daily Holding followup scheduler";
mail.From = new System.Net.Mail.MailAddress("autosupport#powersoft.in");
SmtpClient smtp = new SmtpClient();
smtp.Timeout = 1000000;
smtp.Port = Convert.ToInt32(System.Configuration.ConfigurationManager.AppSettings["Port"]);
smtp.UseDefaultCredentials = true;
smtp.Host = System.Configuration.ConfigurationManager.AppSettings["MailHost"];
smtp.Credentials = new NetworkCredential(mail.From.ToString(), "PS123456");
smtp.EnableSsl = true;
mail.To.Add(new MailAddress("abc#test.com"));
mail.IsBodyHtml = true;
mail.Body = StrPriBody;
DataSet ds = new DataSet();
ds.Tables.Add(table);
ds.Tables[0].TableName = "Post sale follow up entries auto mailer";
SaveFileDialog save = new SaveFileDialog();
save.InitialDirectory = "\\Attachment";
save.RestoreDirectory = true;
ExcelLibrary.DataSetHelper.CreateWorkbook("Employee_Details.xls", ds);
mail.Attachments.Add(new Attachment("Employee_Details.xls"));
smtp.Send(mail);
foreach (Attachment attachments in mail.Attachments)
{
attachments.Dispose();
}
You don't need a SaveFileDialog to do that (and in your code you define it but you are not using it). Just use File.Copy. So, after creating your Workbook here:
ExcelLibrary.DataSetHelper.CreateWorkbook("Employee_Details.xls", ds);
Just add something like:
File.Copy("Employee_Details.xls","\\Attachment\Employee_Details.xls");
1) Why you are using SaveFileDialog? User must choose folder and file name to save to? Then you forgot to "display" dialog, and after user close it - retrieve chosen folder/file name from it and (preferably) use full path (C:\Folder\File...) for CreateWorkbook and new Attachment(...).
2) Are you sure that after call to ExcelLibrary.DataSetHelper.CreateWorkbook this file is actually written to disk with content? May be you need to call some Save() methods? (this is library-specific, read in library docs)
3) Are you sure that after call to ExcelLibrary.DataSetHelper.CreateWorkbook new file is closed/unlocked by writing code? May be you need to Dispose something? (again, check library docs)
4) Are you testing on server (website?) or desktop machine? Check that you can write access to folder where you want to store your file.

Attachment is not going with email

And i am sending mails from below details :
// language -- C#
// import namespace
using System.Web.Mail;
private void SendEmail()
{
const string SERVER = "relay-hosting.secureserver.net";
MailMessage oMail = new System.Web.Mail.MailMessage();
oMail.From = "emailaddress#domainname";
oMail.To = "emailaddress#domainname";
oMail.Subject = "Test email subject";
oMail.BodyFormat = MailFormat.Html; // enumeration
oMail.Priority = MailPriority.High; // enumeration
oMail.Body = "Sent at: " + DateTime.Now;
SmtpMail.SmtpServer = SERVER;
SmtpMail.Send(oMail);
oMail = null; // free up resources
}
Mails are going properly with above details and now i want to add attachment on email.And for that i have added below code :
String sFile = "http://www.demo.com/abc.pdf";
var oAttch = new System.Web.Mail.MailAttachment(sFile);
oMail.Attachments.Add(oAttch);
But it's not adding the attachment in mail.
It's giving error that "URI formats are not supported".
Mail attachment supports only files from the local drive.
If you want to attach a file that is hosted on the web you should download it to your local drive first.
If you have the file in your local drive you can do something like this:
String sFile = "abc.pdf";
var oAttch = new System.Web.Mail.MailAttachment(Server.MapPath(sFile));
oMail.Attachments.Add(oAttch);
You cant use a file from the web. It must be located on your local drive.
Check out MSDN - MailAttachment Constructor (String)

File is used by another process exception C#

I have created an application that generates excel files from information in a database. These files are saved on my HDD in a folder.
After that I attach the files and send them via mail. When I generate another batch of files I delete the old files and then create the new ones.
My problem is when I have generated one batch of files and then send them, and I want to generate another batch I cannot delete the one of the old files, because the mailing method is still holding on to one of the excel files.
Here is my code:
public void SendMailedFilesDKLol() {
string[] sentFiles=Directory.GetFiles(some_Folder);
if(sentFiles.Count()>0) {
System.Net.Mail.SmtpClient client=new System.Net.Mail.SmtpClient("ares");
System.Net.Mail.MailMessage msg=new System.Net.Mail.MailMessage();
msg.From=new MailAddress("system#lol.dk");
msg.To.Add(new MailAddress("lmy#lol.dk"));
msg.Subject="IBM PUDO";
msg.Body=
sentFiles.Count()+" attached file(s) has been sent to the customer(s) in question ";
msg.IsBodyHtml=true;
foreach(string file in sentFiles) {
Attachment attachment=new Attachment(file);
msg.Attachments.Add(attachment);
}
client.Send(msg);
}
}
I have tried to dispose the client element but that didn't help.
Can anyone help me with this?
Both System.Net.Mail.MailMessage & System.Net.Mail.SmtpClient are IDisposable classes. You can try the following,
using (System.Net.Mail.SmtpClient client = new System.Net.Mail.SmtpClient("ares"))
{
using (System.Net.Mail.MailMessage msg = new System.Net.Mail.MailMessage())
{
msg.From = new MailAddress("system#lol.dk");
msg.To.Add(new MailAddress("lmy#lol.dk"));
msg.Subject = "IBM PUDO";
msg.Body = sentFiles.Count() + " attached file(s) has been sent to the customer(s) in question ";
msg.IsBodyHtml = true;
foreach (string file in sentFiles)
{
Attachment attachment = new Attachment(file);
msg.Attachments.Add(attachment);
}
client.Send(msg);
}
}
It sounds like you may not be closing your file stream when generating the excel files or you have them open in excel when trying to email them.
Please can you show your code for generating the excel files.
You need to dispose the Attachment objects.
Example using LINQ:
public void SendMailedFilesDKLol() {
string[] sentFiles=Directory.GetFiles(some_Folder);
if(sentFiles.Count()>0) {
System.Net.Mail.SmtpClient client=new System.Net.Mail.SmtpClient("ares");
System.Net.Mail.MailMessage msg=new System.Net.Mail.MailMessage();
msg.From=new MailAddress("system#lol.dk");
msg.To.Add(new MailAddress("lmy#lol.dk"));
msg.Subject="IBM PUDO";
msg.Body=
sentFiles.Count()+" attached file(s) has been sent to the customer(s) in question ";
msg.IsBodyHtml=true;
var attachments = sentFiles.Select(f => new Attachment(f)).ToList();
attachments.ForEach(a => msg.Attachments.Add(a));
client.Send(msg);
attachments.ForEach(a => a.Dispose());
}
}

SMTP Send is locking up my files - c#

I have a function thats sending messages ( a lot of them) and their attachments.
It basically loops through a directory structure and creates emails from a file structure for example
c:\emails\message01
\attachments
c:\emails\message02
\attachments
The creation of the messages takes place using .net c#, standard stuff.
After all messages are created... I have another function that runs directly afterwards that copies the message folder to another location.
Problem is - files are locked...
Note: I'm not moving the files, just copying them....
Any suggestions on how to copy locked files, using c#?
Update
I have this add attachments method
private void AddAttachments(MailMessage mail)
{
string attachmentDirectoryPath = "c:\messages\message1";
DirectoryInfo attachmentDirectory = new DirectoryInfo(attachmentDirectoryPath);
FileInfo[] attachments = attachmentDirectory.GetFiles();
foreach (FileInfo attachment in attachments)
{
mail.Attachments.Add(new Attachment(attachment.FullName));
}
}
How are you reading the files to create the email message? They should be opened as read-only, with a FileShare set to FileShare.ReadWrite... then they shouldn't be locked. If you are using a FileStream you should also wrap your logic in the using keyword so that the resource is disposed properly.
Update:
I believe disposing the mail message itself will close resources within it and unlock the files:
using (var mail = new MailMessage())
{
AddAttachments(mail);
}
// File copy code should work here
hate answering my own post, but yeah for the next poor guy who has this problem here is the fix:
AFTER YOU SEND THE MESSAGE
// Send the mail
client.Send(message);
//Clean up attachments
foreach (Attachment attachment in message.Attachments)
{
attachment.Dispose();
}
Dispose the attachments... clears the lock, and messages will still be sent with attachments. Dispose DOES NOT delete the files, just clears the attachments :)
Are you closing the files after you finish reading them? If you open them for reading, but don't close them when you're done, it should keep a lock on it until the program exits and automatically closes all the files.
MailMessage email = new MailMessage();
email.From = txtFrom.Text;
email.To = txtToEmail.Text;
email.Subject = txtMSubject.Text;
email.Body = txtBody.Text;
SmtpClient mailClient = new SmtpClient();
mailClient.Host = "smtp.emailAddress";
mailClient.Port = 2525;
mailClient.Send(email );
email.Dispose();
// After Disposing the email object you can call file delete
if (filePath != "")
{
if (System.IO.File.Exists(filePath))
{
System.IO.File.Delete(filePath);
}
}
I see this a lot when sending attachments. I normally use something like the following:
In the code that moves the files to a different location, you can use the following pattern:
Inside the loop for looping through the files
bool FileOk = false;
while (!FileOk)
{
try
{
// code to move the file
FileOk = true;
}
catch(Exception)
{
// do nothing or write some code to pause the thread for a few seconds.
}
}

Categories

Resources