ASP.NET 5 / MVC 6 /C#: Close File Path after usage - c#

i've got a problem with closing a temporary file. In my method I'm, generating an ics file, write text in it and then send it using MimeMail. The problem is that I don't know how to close the path so that I can access it to delete it after the mail was send. And MimeMail does not provide a solution like message.Dispose() or message.Close().
Here is my code:
public void SendEmailWithICal(string toEmailAddress, string subject, string textBody)
{
var message = new MimeMessage();
message.From.Add(
new MailboxAddress("Chronicus Dev", this.UserName));
message.To.Add(new MailboxAddress(toEmailAddress.Trim(), toEmailAddress.ToString()));
message.Subject = subject;
CalenderItems iCalender = new CalenderItems();
iCalender.GenerateEvent("Neuer Kalendereintrag");
var termin = iCalender.iCal;
string path = "TempIcsFiles/file.ics";
if (File.Exists(path))
{
File.Delete(path);
}
{
// Create File and Write into it
FileStream fs = new FileStream(path, FileMode.OpenOrCreate);
StreamWriter str = new StreamWriter(fs);
str.BaseStream.Seek(0, SeekOrigin.End);
str.Write(termin.ToString());
//Close Filestream and Streamwriter
str.Flush();
str.Dispose();
fs.Dispose();
//Add as Attachment
var attachment = new MimePart("image", "gif")
{
ContentObject = new ContentObject(File.OpenRead(path), ContentEncoding.Default),
ContentDisposition = new ContentDisposition(ContentDisposition.Attachment),
ContentTransferEncoding = ContentEncoding.Base64,
FileName = Path.GetFileName(path)
};
var body = new TextPart("plain")
{
Text = "Meine ICal Mail"
};
//Configure Email
var multipart = new Multipart("mixed");
multipart.Add(body);
multipart.Add(attachment);
message.Body = multipart;
//Send Email
using (var client = new SmtpClient())
{
client.Connect(HostName, Port, false);
client.Authenticate(UserName, Password);
client.Send(message);
client.Disconnect(true);
}
//TODO Close File
//Trying to Delete, but Exception
File.Delete(path);
}
}
Thanks for any help!

Try to relocate the File.OpenRead(path),
and wrap the whole message object in using() like this:
public void SendEmailWithICal(string toEmailAddress, string subject, string textBody)
{
CalenderItems iCalender = new CalenderItems();
iCalender.GenerateEvent("Neuer Kalendereintrag");
var termin = iCalender.iCal;
string path = "TempIcsFiles/file.ics";
if (File.Exists(path))
{
File.Delete(path);
}
//Create file and write to it
using (var fs = new FileStream(path, FileMode.OpenOrCreate))
{
using (var str = new StreamWriter(fs))
{
str.BaseStream.Seek(0, SeekOrigin.End);
str.Write(termin.ToString());
//Close Filestream and Streamwriter
str.Flush();
}
}
//Compose the message
using (var read_stream = File.OpenRead(path))
{
using (var message = new MimeMessage())
{
message.From.Add(new MailboxAddress("Chronicus Dev", this.UserName));
message.To.Add(new MailboxAddress(toEmailAddress.Trim(), toEmailAddress.ToString()));
message.Subject = subject;
//Add as Attachment
var attachment = new MimePart("image", "gif")
{
ContentObject = new ContentObject(read_stream, ContentEncoding.Default),
ContentDisposition = new ContentDisposition(ContentDisposition.Attachment),
ContentTransferEncoding = ContentEncoding.Base64,
FileName = Path.GetFileName(path)
};
var body = new TextPart("plain")
{
Text = "Meine ICal Mail"
};
//Configure Email
var multipart = new Multipart("mixed");
multipart.Add(body);
multipart.Add(attachment);
message.Body = multipart;
//Send Email
using (var client = new SmtpClient())
{
client.Connect(HostName, Port, false);
client.Authenticate(UserName, Password);
client.Send(message);
client.Disconnect(true);
}
}
}
//Delete temporary file
File.Delete(path);
}
this should guarantee a closed file, assuming that client.Send is an entirely synchronous operation.
see also this possible duplicate https://stackoverflow.com/questions/1296380/smtp-send-is-locking-up-my-files-c-sharp

Use this code:
File.Create(FilePath).Close();
File.WriteAllText(FileText);

Related

Create an email with an attachment on Server for user to download

I have a program on the server that creates pdf sql reports and I need to have them so users can email them out. First off before everything gets automated I want them to be able to view the email and adjust it as needed.
Im been using office.interop.outlook but now that isn’t working on the server as people have told me earlier. To view the documents I put all the selected PDF reports in a .zip file and the user downloads the zip. Now I was thinking of doing the same thing for emails.
Creating a .zip file that contains emails with the pdf reports as the attachment.
How could I create am email draft with an attachment the user could download and open on their own machine? I can successfully create a text file and download it. When I try to use Office.Interop.Outlook I cannot create the ‘MailItem’ and convert it to a byte array to put it in return File(). What would you suggest? Locally everything works perfectly.
I also read online about creating an .eml file and people cam open this as if it were and email. Everyone has Outlook in the company. Outlook has .msg files for its email.
Heres some stuff ive tried
public ActionResult Testtxt()
{
var data = "Here is a string with information in it";
var byteArray = System.Text.Encoding.ASCII.GetBytes(data);
var memorystream = new MemoryStream(byteArray);
return File(memorystream, "text/plain", "txtname.txt");
}
public void OutlookTest() // Errors when creating the email (permission rights)
{
ServiceResponse servRespObj = new ServiceResponse();
//string downloadsPath = new KnownFolder(KnownFolderType.Downloads).Path;
/// Test Mail on Server /* mail draft = Untitled.msg */
/// "application/vsd.ms-outlook" as MIME type.
/// ".msg" as extension
/// 1. FilePath, 2. ContentType(MIME), 3.FileName return File(1,2,3); top=FileResult
OutlookApp outlookapp = new OutlookApp();
MailItem mailItem = outlookapp.CreateItem(OlItemType.olMailItem);
mailItem.Subject = "This is a TEST msg - Subject02";
mailItem.Body = "msg body02";
//byte[] fileByteArray = System.IO.File.ReadAllBytes(mailItem);
var byteArray = System.Text.Encoding.ASCII.GetBytes(mailItem);
//return File(mailItem, "application/vsd.ms-outlook", "testMessage.msg");
//mailItem.SaveAs(downloadsPath, OlSaveAsType.olMSG);
//mailItem.Save();
}
public ActionResult EmailDraft2()
{
byte[] fileByteArray = null;
string timeNow = DateTime.Now.ToString("MM-dd-yyyy-HHmmss");
OutlookApp application = new OutlookApp();
MailItem mailItem = application.CreateItem(OlItemType.olMailItem);
mailItem.Subject = "test subject draft";
mailItem.Body = "test body draft";
using(MemoryStream stream = new MemoryStream())
{
/// Creates the .zip file.
using(ZipArchive archive = new ZipArchive(stream, ZipArchiveMode.Create, true))
{
/// Iterates through the files
//foreach
/// Creates an archive for the .zip // & extension
ZipArchiveEntry archiveEntry = archive.CreateEntry("filename" + ".msg");
/// Adds the archive to the .zip
//using(MemoryStream fileStream = new MemoryStream(mailItem.))
}
}
return null;
}
public ActionResult CreateEMLemail()
{
string senderEmail = "Test#test.test.test";
var mailMessage = new MailMessage();
mailMessage.From = new MailAddress(senderEmail);
mailMessage.To.Add("To_EmailSend#msn.com");
mailMessage.Subject = "EML TEST MAIL SUBJECT";
mailMessage.Body = "EML TEST MAIL BODY";
var stream = new MemoryStream();
ToEMLstream(mailMessage, stream, senderEmail);
stream.Position = 0;
return File(stream, "message/rfc822", "emlTESTmessage.eml");
}
private void ToEMLstream(MailMessage msg, Stream stream, string fromSender)
{
using(var client = new SmtpClient())
{
var id = 0;
//var tempFolder = Path.Combine(Path.GetTempPath(), Assembly.GetExecutingAssembly().GetName().Name);
//tempFolder = Path.Combine(tempFolder, "EMLtempFolder");
var downloads = new KnownFolder(KnownFolderType.Downloads).Path;
string timeNow = DateTime.Now.ToString("MM-dd-yyyy-HHmmss");
var newFolder = Path.Combine(downloads, timeNow);
//if (!Directory.Exists(tempFolder))
if (!Directory.Exists(newFolder))
{
//Directory.CreateDirectory(tempFolder);
Directory.CreateDirectory(newFolder);
}
//client.UseDefaultCredentials = true;
//client.DeliveryMethod = SmtpDeliveryMethod.SpecifiedPickupDirectory;
//client.PickupDirectoryLocation = tempFolder;
//client.Send(msg);
//string newFile = Path.Combine(tempFolder, "emlTestmail.eml");
string newFile = Path.Combine(newFolder, "emlTestmail.eml");
//using (var streamr = new StreamReader(tempFolder))
using (var streamr = new StreamReader(newFolder))
{
using (var streamw = new StreamWriter(newFile))
{
string line;
while((line = streamr.ReadLine()) != null)
{
if(!line.StartsWith("X-Sender:") && !line.StartsWith("From:") &&
!line.StartsWith("X-Receiver: " + fromSender) &&
!line.StartsWith("To: " + fromSender))
{
streamw.WriteLine(line);
}
}
}
}
{
using(var filesteam = new FileStream(newFile, FileMode.OpenOrCreate))
{
filesteam.CopyTo(stream);
}
}
}
}
I got it working!
I can create an email as an .eml mail message. Attach a report to it and save the new email to the server.
Thank you all for all the help!
Here is what I used.
$("#btnEmailTest").on("click", function () {
$.ajax({
type: "POST",
url: '#Url.Action("Testemail2", "Service")',
contentType: "application/json",
success: function (data) {
//window.location
alert("success : " + data);
},
error: function (xhr, status, error) {
//alert("Error " + xhr.responseText + " \n " + error);
}
})
});
[HttpPost]
public ActionResult Testemail2()
{
string senderEmail = "testc#send.com";
var mailMessage = new MailMessage();
mailMessage.From = new MailAddress(senderEmail);
mailMessage.To.Add("testTo#to.com");
mailMessage.Subject = "Test EML Subject012";
mailMessage.Body = "Test EML Body012";
/// mark as DRAFT
mailMessage.Headers.Add("X-Unsent", "1");
//ATTACHMENTS
var stream = new MemoryStream();
EML_Stream(mailMessage, stream, senderEmail);
stream.Position = 0;
string variable = "";
if(TempData["rootTest"] != null)
{
variable = TempData["rootTest"].ToString();
}
return Json(variable);
//return File(stream, "message/rfc822", "Test_Email.eml");
}
private void EML_Stream(MailMessage msg, Stream str, string fromEmail)
{
string rootTemp = "";
using(var client = new SmtpClient())
{
try
{
string timeNow = DateTime.Now.ToString("MM-dd-yyyy-HHmmss");
var tempfolder = Path.Combine(Path.GetTempPath(), Assembly.GetExecutingAssembly().GetName().Name);
//tempfolder = Path.Combine("MailTest");
// Create temp folder to hold .eml file
tempfolder = Path.Combine(tempfolder, timeNow);
if (!Directory.Exists(tempfolder))
{
Directory.CreateDirectory(tempfolder);
}
rootTemp = tempfolder;
TempData["rootTest"] = rootTemp;
client.UseDefaultCredentials = true;
client.DeliveryMethod = SmtpDeliveryMethod.SpecifiedPickupDirectory;
client.PickupDirectoryLocation = tempfolder;
client.Send(msg);
}
catch (System.Exception ex)
{
TempData["Error"] = ex.Message.ToString();
}
// C:/temp/maildrop should contain .eml file.
///C:\temp\maildrop\
//var filePath = Directory.GetFiles("C:\\temp\\maildrop\\").Single();
string filePath = Directory.GetFiles(rootTemp).Single();
/// Create new file and remove all lines with 'X-Sender:' or 'From:'
string newFile = Path.Combine(rootTemp, "testemlemail.eml");
using (var reader = new StreamReader(filePath))
{
using (var writer = new StreamWriter(newFile))
{
string line;
while ((line = reader.ReadLine()) != null)
{
if (!line.StartsWith("X-Sender:") &&
!line.StartsWith("From:") &&
!line.StartsWith("X-Receiver: " + fromEmail) &&
!line.StartsWith("To: " + fromEmail))
{
writer.WriteLine(line);
}
}
}
}
using(var fs = new FileStream(newFile, FileMode.Open))
{
fs.CopyTo(str);
}
}
}

How do I get my PDF email attachment to attach correctly as a PDF?

Below I've added a screenshot of the attachment as it appears in the email.
It opens fine in any PDF reader.
How do I get it to present as an actual PDF? I feel as though I've missed something small...
Here's my code:
public ActionResult SendInvoice(SendInvoiceViewModel model)
{
var Invoice = db.Invoices.FirstOrDefault(x => x.Id == model.Id);
MemoryStream ms = new MemoryStream(Invoice.Document);
Attachment Data = new Attachment(ms, MediaTypeNames.Application.Pdf);
ContentDisposition Disposition = Data.ContentDisposition;
Disposition.CreationDate = Invoice.Date;
Disposition.ModificationDate = Invoice.Date;
Disposition.ReadDate = Invoice.Date;
SendInvoiceMail(model.EmailAddress, Invoice.Number, model.EmailMessage, Data);
}
private void SendInvoiceMail(string emailAddress, string invoiceNumber, string message, Attachment attachment)
{
using (MailMessage Message = new MailMessage())
{
Message.From = new MailAddress("accounts############");
Message.Subject = String.Format("Your store invoice {0}", invoiceNumber);
Message.To.Add(new MailAddress(emailAddress));
Message.Body = message;
Message.Attachments.Add(attachment);
SmtpClient smtp = new SmtpClient("mail.############", 587);
smtp.Credentials = new NetworkCredential("info###########", "##########");
smtp.Send(Message);
};
}
So what did I miss?
Try using the 3-parameter version of the Attachment() constructor. The second parameter lets you give a file name. That file name should end in .pdf.
Try
public ActionResult SendInvoice(SendInvoiceViewModel model)
{
var Invoice = db.Invoices.FirstOrDefault(x => x.Id == model.Id);
MemoryStream ms = new MemoryStream(Invoice.Document);
//Construct a file name for the attachment
var filename = string.Format("{0}.pdf", Invoice.Number);
Attachment Data = new Attachment(ms, filename, MediaTypeNames.Application.Pdf);
ContentDisposition Disposition = Data.ContentDisposition;
Disposition.CreationDate = Invoice.Date;
Disposition.ModificationDate = Invoice.Date;
Disposition.ReadDate = Invoice.Date;
SendInvoiceMail(model.EmailAddress, Invoice.Number, model.EmailMessage, Data);
}
Where you include the file name for the attachment.

Delete attached files after sending mail via SmtpClient ( ASP.NET MVC)

I'm working on a website that can send a form with multiple files attached/upload, the files that are being attached is stored in the App_Data/uploads folder. Is there a chance that the file in the App_Data/uploads folder will be deleted right after it's send in the email? Thank you for your help. This is my controller:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Index(EmailFormModel model, IEnumerable<HttpPostedFileBase> files)
{
if (ModelState.IsValid)
{
List<string> paths = new List<string>();
foreach (var file in files)
{
if (file.ContentLength > 0)
{
var fileName = Path.GetFileName(file.FileName);
var path = Path.Combine(Server.MapPath("~/App_Data/uploads"), fileName);
file.SaveAs(path);
paths.Add(path);
}
}
var message = new MailMessage();
foreach (var path in paths)
{
var fileInfo = new FileInfo(path);
var memoryStream = new MemoryStream();
using (var stream = fileInfo.OpenRead())
{
stream.CopyTo(memoryStream);
}
memoryStream.Position = 0;
string fileName = fileInfo.Name;
message.Attachments.Add(new Attachment(memoryStream, fileName));
}
//Rest of business logic here
string EncodedResponse = Request.Form["g-Recaptcha-Response"];
bool IsCaptchaValid = (ReCaptcha.Validate(EncodedResponse) == "True" ? true : false);
if (IsCaptchaValid)
{
var body = "<p><b>Email From:</b> {0} ({1})</p><p><b>Subject:</b> {2} </p><p><b>Message:</b></p><p>{3}</p><p><b>Software Description:</b></p><p>{4}</p>";
message.To.Add(new MailAddress("***#gmail.com"));
message.From = new MailAddress("***#ymailcom");
message.Subject = "Your email subject";
message.Body = string.Format(body, model.FromName, model.FromEmail, model.FromSubject, model.Message, model.Desc);
message.IsBodyHtml = true;
using (var smtp = new SmtpClient())
{
var credential = new NetworkCredential
{
UserName = "***#gmail.com",
Password = "***"
};
smtp.Credentials = credential;
smtp.Host = "smtp.gmail.com";
smtp.Port = 587;
smtp.EnableSsl = true;
await smtp.SendMailAsync(message);
ViewBag.Message = "Your message has been sent!";
ModelState.Clear();
return View("Index");
}
} else
{
TempData["recaptcha"] = "Please verify that you are not a robot!";
}
} return View(model);
}
You can use SmtpClient's SendCompleted event to delete the file after sending:
smtp.SendCompleted += (s, e) => {
//delete attached files
foreach (var path in paths)
System.IO.File.Delete(path);
};
so the sending part should look like this:
using (var smtp = new SmtpClient())
{
var credential = new NetworkCredential
{
UserName = "***#gmail.com",
Password = "***"
};
smtp.Credentials = credential;
smtp.Host = "smtp.gmail.com";
smtp.Port = 587;
smtp.EnableSsl = true;
smtp.SendCompleted += (s, e) => {
//delete attached files
foreach (var path in paths)
System.IO.File.Delete(path);
};
await smtp.SendMailAsync(message);
ViewBag.Message = "Your message has been sent!";
ModelState.Clear();
return View("Index");
}

How to delete the uploaded files in the "/App_Data/uploads" folder ASP.NET MVC

I can upload/attach files when I'm sending message in email. The files are being stored in the App_Data/uploads folder, so when I'm trying to send multiple files it takes long time before I can send it. I think it's because the folder already have many files, so I want to delete the files in folder when it's already send in email. Please help me. I'm just new with this kind of stuff. Thank you! Here's the controller:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Index(EmailFormModel model, IEnumerable<HttpPostedFileBase> files)
{
if (ModelState.IsValid)
{
List<string> paths = new List<string>();
foreach (var file in files)
{
if (file.ContentLength > 0)
{
var fileName = Path.GetFileName(file.FileName);
var path = Path.Combine(Server.MapPath("~/App_Data/uploads"), fileName);
file.SaveAs(path);
paths.Add(path);
}
}
var message = new MailMessage();
foreach (var path in paths)
{
var fileInfo = new FileInfo(path);
var memoryStream = new MemoryStream();
using (var stream = fileInfo.OpenRead())
{
stream.CopyTo(memoryStream);
}
memoryStream.Position = 0;
string fileName = fileInfo.Name;
message.Attachments.Add(new Attachment(memoryStream, fileName));
}
//Rest of business logic here
string EncodedResponse = Request.Form["g-Recaptcha-Response"];
bool IsCaptchaValid = (ReCaptcha.Validate(EncodedResponse) == "True" ? true : false);
if (IsCaptchaValid)
{
var body = "<p>Email From: {0} ({1})</p><p>Subject: {2} </p><p>Message:</p><p>{3}</p>";
message.To.Add(new MailAddress("***#gmail.com")); // replace with valid value
message.From = new MailAddress("***#ymailcom"); // replace with valid value
message.Subject = "Your email subject";
message.Body = string.Format(body, model.FromName, model.FromEmail, model.FromSubject, model.Message);
message.IsBodyHtml = true;
using (var smtp = new SmtpClient())
{
var credential = new NetworkCredential
{
UserName = "***#gmail.com", // replace with valid value
Password = "***" // replace with valid value
};
smtp.Credentials = credential;
smtp.Host = "smtp.gmail.com";
smtp.Port = 587;
smtp.EnableSsl = true;
await smtp.SendMailAsync(message);
//return RedirectToAction("Sent");
ViewBag.Message = "Your message has been sent!";
//TempData["message"] = "Message sent";
ModelState.Clear();
return View("Index");
}
}
else
{
TempData["recaptcha"] = "Please verify that you are not a robot!";
}
}
return View(model);
}
intially check for file existence then try below code
File.Delete("~/App_Data/uploads/XXXXX.xls");
Before to send on email you have to check first ...
if (System.IO.File.Exists(fullPath of your file))
{
System.IO.File.Delete(fullPath of your file);
}
try this:
System.IO.DirectoryInfo di = new DirectoryInfo(path);
foreach (FileInfo file in di.GetFiles())
{
file.Delete();
}
I strongly recommend to not use App_Data folder for storing any files , by convention is created only for storing database files.

How to send email using GMAIL API having HTML body + attachment in ASP.NET

var msg = new AE.Net.Mail.MailMessage
{
Subject = subject,
Body = bodyhtml,
From = new System.Net.Mail.MailAddress("myemail")
};
foreach (string add in vendorEmailList.Split(','))
{
if (string.IsNullOrEmpty(add))
continue;
msg.To.Add(new System.Net.Mail.MailAddress(add));
}
msg.ReplyTo.Add(msg.From); // Bounces without this!!
msg.ContentType = "text/html";
////attachment code
foreach (string path in attachments)
{
var bytes = File.ReadAllBytes(path);
string mimeType = MimeMapping.GetMimeMapping(path);
AE.Net.Mail.Attachment attachment = new AE.Net.Mail.Attachment(bytes, mimeType, Path.GetFileName(path), true);
msg.Attachments.Add(attachment);
}
////end attachment code
var msgStr = new StringWriter();
msg.Save(msgStr);
Message message = new Message();
message.Raw = Base64UrlEncode(msgStr.ToString());
var result = gmailService.Users.Messages.Send(message, "me").Execute();
This code is working without attachment but with attachment instead of attachment directly byte[] is appearing in inbox.
If i remove msg.ContentType = "text/html" this line then it is working but html not rendering in email, appearing as plain text.
I want to send both HTML body and attachment, Please help.
MailMessage mail = new MailMessage();
mail.Subject = subject;
mail.Body = bodyhtml;
mail.From = new MailAddress("myemail");
mail.IsBodyHtml = true;
foreach (string add in vendorEmailList.Split(','))
{
if (string.IsNullOrEmpty(add))
continue;
mail.To.Add(new MailAddress(add));
}
foreach (string add in userEmailList.Split(','))
{
if (string.IsNullOrEmpty(add))
continue;
mail.CC.Add(new MailAddress(add));
}
foreach (string path in attachments)
{
//var bytes = File.ReadAllBytes(path);
//string mimeType = MimeMapping.GetMimeMapping(path);
Attachment attachment = new Attachment(path);//bytes, mimeType, Path.GetFileName(path), true);
mail.Attachments.Add(attachment);
}
MimeKit.MimeMessage mimeMessage = MimeMessage.CreateFromMailMessage(mail);
Message message = new Message();
message.Raw = Base64UrlEncode(mimeMessage.ToString());
var result = gmailService.Users.Messages.Send(message, "me").Execute();
I found solution after lot of efforts. Instead of AE.Net.Mail.MailMessage used System.Net.Mail.MailMessage and MimeKit to convert it to raw string. And now html body with attachment is working fine.
try adding IsBodyHtml = true
new AE.Net.Mail.MailMessage
{
Subject = subject,
Body = bodyhtml,
From = new System.Net.Mail.MailAddress("myemail")
IsBodyHtml = true
};

Categories