file in use after sending email with attachment - c#

I am sending a file through .net's smtp as such:
private void SendMail()
{
var _msg = new MailMessage();
const string cEmailUsername = "xxxxxx";
const string cEmailPassword = "zzzzzz";
const string cSmtpClient = "yyyyyyy";
try
{
using (var smtp = new SmtpClient(cSmtpClient))
{
_msg.From = string.IsNullOrEmpty(Configuration.CompanyEmailAddress)
? new MailAddress(cEmailUsername)
: new MailAddress(Configuration.CompanyEmailAddress.ToLower());
_msg.Subject = string.Format("Request for .Net Support - {0} - {1}", Configuration.CompanyID,
Configuration.GetCompanyName());
_msg.Body = string.Format("Propane.exe date: {0}{1}{1}{2}", Configuration.VersionDate, Environment.NewLine,
"Check parsing log file attached.");
_msg.To.Add("eric#suburbansoftware.com");
_msg.Attachments.Add(new Attachment(_logFile));
var cred2 = new NetworkCredential(cEmailUsername, cEmailPassword);
smtp.Port = 587;
smtp.Credentials = cred2;
smtp.Timeout = 0;
smtp.Send(_msg);
}
var oldfile = _logFile + ".old";
if (File.Exists(oldfile))
{
File.Delete(oldfile);
}
File.Move(_logFile,oldfile);
}
catch (Exception ex)
{
richTextBox_Message.Text += ex.Message;
}
}
I am getting a file in use exception when I get to the file.move. If I comment out the using portion, the move works just fine.
Is there a way around this or am I doing it wrong?

Using works just with smtp, not with _msg. This variable is the one containing the attachment and is not disposed. Include this code right after finishing the using part and everything should be fine:
_msg.Dispose();
_msg = null;

Related

FileStream Attachment To Email C#

I wrote a code to make attachments for email sending, but I cannot understand how to make it not only for txt files. I know that all the binary files are broken because of "File.OpenText" in my code. Someone can explain to me, how to make it for all files, not only for txt.
public async Task<ResponseData> SendEmail(VictimData victimData, SmtpData senderData, LetterData letter)
{
ResponseData response = new ResponseData();
BodyBuilder bodyBuilder = new BodyBuilder();
string newAttachment = "";
try
{
MimeMessage message = new MimeMessage();
message.From.Add(new MailboxAddress(senderData.senderName, senderData.senderEmail));
message.To.Add(new MailboxAddress("", victimData.email));
/*message.Bcc.Add(new MailboxAddress(senderData.senderName, senderData.senderEmail));
message.ReplyTo.Add(new MailboxAddress(senderData.senderName, senderData.senderEmail));*/
message.Subject = letter.subject;
if (letter.isHtml)
{
bodyBuilder.HtmlBody = letter.body;
}
else
{
bodyBuilder.TextBody = letter.body;
}
foreach (var attachment in letter.attachment)
{
newAttachment = ReadAndReplaceAttachment(attachment.filePath, victimData.email, attachment.fileName);
bodyBuilder.Attachments.Add(newAttachment);
File.Delete(newAttachment);
Console.WriteLine(newAttachment);
}
message.Body = bodyBuilder.ToMessageBody();
await client.SendAsync(message);
response.status = true;
response.messages = "";
return response;
}
catch (Exception ex)
{
response.messages = ex.Message;
response.status = false;
return response;
}
}
private string ReadAndReplaceAttachment(string filePath, string email, string newFileName)
{
Replacer replacer = new Replacer();
string tempFile = Path.Combine(Helpers.tempPath, replacer.DoReplace(newFileName, email));//Path.GetTempPath() + Guid.NewGuid().ToString() + Path.GetExtension(filePath);
string contentResult = "";
using (StreamReader sr = File.OpenText(filePath))
{
contentResult = sr.ReadToEnd();
contentResult = replacer.DoReplace(contentResult, email);
sr.Close();
}
using (var tw = new StreamWriter(tempFile, true))
{
tw.Write(contentResult);
}
return tempFile;
}
You would need to change your code to only call your ReadAndReplaceAttachment() method for txt files and not for any other type of file. For non-text files, you would just attach the original file referenced by attachment.filePath.

Closedxml: can't download file and immediately send it via mail

I want to download an excel file and automatically send the file to a mailadress aswell. Downloading the file works, but when I include the code for sending mails, it throws a FileNotFoundException: 'Could not find file 'C:\Users\User\source\repos\Project\Taijitan\Taijitan\O soto gari.xlsx'.'.
I noticed that when downloading the file, it automatically goes to the Downloads folder on my pc. When I uncomment the mail code, it doesn't seem to download, instead it just loads before throwing the error I mentioned above. I tried using Path.GetFullPath(name) to find the excel file so that I don't have to hardcode any paths (in case any of my colleagues have a different path), but it doesn't seem to work.
Controller
public IActionResult GenerateList(int id)
{
Lesson lesson = _lessonRepository.GetBy(id);
var download = lesson.GetCommentsList();
string file = lesson.Name + ".xlsx";
MailSender.SendListMail(lesson.Name, file);
return download;
}
Generate excel + download
public List<Comment> Comments { get; set; }
public IActionResult GetCommentsList()
{
List<string> list = new List<string>();
var wb = new XLWorkbook();
var ws = wb.Worksheets.Add("Comments");
foreach (var comment in Comments)
{
list.Add(comment.Body);
}
string name = Name + "comment";
ws.Cell(1, 1).Value = name;
ws.Range(1, 1, 1, 1).AddToNamed("Titles");
var CommentsRange = ws.Cell(2, 1).InsertData(list.AsEnumerable());
var titlesStyle = wb.Style;
titlesStyle.Font.Bold = true;
titlesStyle.Alignment.Horizontal = XLAlignmentHorizontalValues.Center;
titlesStyle.Fill.BackgroundColor = XLColor.Blue;
titlesStyle.Font.FontColor = XLColor.White;
wb.NamedRanges.NamedRange("Titles").Ranges.Style = titlesStyle;
ws.Columns().AdjustToContents();
wb.SaveAs(name + ".xlsx");
using (var stream = new MemoryStream())
{
wb.SaveAs(stream);
stream.Flush();
return new FileContentResult(stream.ToArray(),
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
{
FileDownloadName = name + ".xlsx"
};
}
}
MailSender
public static void SendListMail(string list, string file)
{
MailAddress Sender = new MailAddress("SenderEmail#gmail.com", "CommentsSender");
MailAddress Receiver = new MailAddress("ReceiverEmail#gmail.com", "Comments inbox");
const string SenderPassword = "password123";
string Attachment = Path.GetFullPath(file);
SmtpClient smtp = new SmtpClient
{
Host = "smtp.gmail.com",
Port = 587,
EnableSsl = true,
DeliveryMethod = SmtpDeliveryMethod.Network,
UseDefaultCredentials = false,
Credentials = new NetworkCredential(Sender.Address, SenderPassword),
Timeout = 30000
};
using (MailMessage message = new MailMessage(Sender, Receiver)
{
Subject = list,
Body = "List in attachment",
Attachments = {new Attachment(Attachment)}
})
{
smtp.Send(message);
}
}
I'm trying to figure out where it goes wrong and how I can solve this.
My guess is it has something to do with synchronization (don't send the mail until the download is complete) and Path.GetFullPath() not checking outside the solutionfolder.
EDIT
Just noticed that when I try to send an email without the attachment, it sends the mail, but doesn't download anything, and the loading icon in the tab keeps spinning.
EDIT 2 Figured out the first problem, the placement of the return statement in the download method caused a loop.
Now I'm still having the could not find file error.
Problem turned out to be a dumb mistake. File got saved with the value of 'name' (file.Name + "comment.xlsx", but the download/email sender was looking for file.Name + ".xlsx" (didn't have "comment" in its name)

Cannot send email from server

I am trying to make a .net core application that send me an email from an URL.
It works perfectly in my local machine but when i deploy it to my server IIS throws me the next exception:
Insufficient system storage. The server response was: 4.3.1 Insufficient system resources
I don't have this exception when i test it on my machine and the email send correctly, only in the IIS Server is there any configuration that my server need?
here is my code:
MailController.cs
[EnableCors("MyPolicy")]
[Produces("application/json")]
[Route("api/Mail")]
public class MailController : Controller
{
[HttpPost("Send")]
public string Send([FromBody]Correo mail)
{
try
{
MailMessage data = new MailMessage();
data.Body = mail.Body;
if (mail.BodyEncoding != null)
data.BodyEncoding = mail.BodyEncoding;
data.BodyTransferEncoding = mail.BodyTransferEncoding;
data.DeliveryNotificationOptions = mail.DeliveryNotificationOptions;
if (mail.HeadersEncoding != null)
data.HeadersEncoding = mail.HeadersEncoding;
data.Priority = mail.Priority;
if (mail.SubjectEncoding != null)
data.SubjectEncoding = mail.SubjectEncoding;
if (mail.Headers != null)
foreach (NameValueCollection header in mail.Headers)
{
data.Headers.Add(header);
}
if (mail.Attachments != null)
foreach (String att in mail.Attachments)
{
Attachment attachment = new Attachment(att);
data.Attachments.Add(attachment);
}
if (mail.CC != null)
foreach (String cc in mail.CC)
{
data.CC.Add(cc);
}
data.From = new MailAddress(mail.From);
data.IsBodyHtml = mail.IsBodyHtml;
data.Subject = mail.Subject;
foreach (String to in mail.To)
{
data.To.Add(to);
}
SmtpClient smtp = new SmtpClient("<IP of SMTP server>");
smtp.UseDefaultCredentials = true;
smtp.DeliveryMethod = SmtpDeliveryMethod.Network;
smtp.Send(data);
data.Dispose();
return "Done!";
}
catch (Exception e)
{
return "Mail not send: " + e.Message;
}
}
}
also i send this from an HttpClient from any other code...
AuthOController.cs - Recovery method
[HttpPost("Recovery/{userName}")]
public async Task<IActionResult> Recovery(String userName)
{
try
{
Correo sender = new Correo();
...
...
...
var myContent = JsonConvert.SerializeObject(sender);
var buffer = Encoding.UTF8.GetBytes(myContent);
var byteContent = new ByteArrayContent(buffer);
byteContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");
HttpClient httpClient = new HttpClient();
var result = await httpClient.PostAsync("http://MailSender/api/Mail/Send", byteContent);
var contents = await result.Content.ReadAsStringAsync();
}
return Ok("Done!");
}
catch (Exception e)
{
return BadRequest(Errors.AddErrorToModelState("recovery_failure", "There was an error in the service: " + e.Message, ModelState));
}
}
data.From = new MailAddress(mail.From);
this line create new object, Change this
For detail help check here

using async/await send email and delete the resource checking condition

I want to send email using c# async/await and the program deletes the attached file from computer depending on the flag "deleteFile". Whatever the value of deleteFile flag the email is delivered successfully but when I set deleteFile to true I am getting the following exception. I have to send two separate emails and I need to delete the file only after second mail.
An unhandled exception of type 'System.IO.IOException' occurred in
mscorlib.dll
Additional information: The process cannot access the file
'C:\Uploads\TestFile.txt' because it is being used by another process.
Could you please help me to resolve the issue?
My console application code is:
using System;
namespace SendMailAsyncDemo
{
class Program
{
private static string filePath = #"C:\Uploads\";
static void Main(string[] args)
{
Sender mailSender = new Sender();
mailSender.SendEmail("myemail#gmail.com", "Async mail with attachment", "Async mail with attachment body goes here ...", filePath + "TestFile.txt", false);
mailSender.SendEmail("anotheremail#gmail.com.com", "Async mail with attachment", "Async mail with attachment body goes here ...", filePath + "TestFile.txt", true);
Console.WriteLine("Email sent successfully!!!");
Console.ReadLine();
}
}
}
I have a Sender class to send email:
using System;
using System.IO;
using System.Net.Mail;
using System.Text;
using System.Threading.Tasks;
namespace SendMailAsyncDemo
{
public class Sender
{
public void SendEmail(string toEmail, string title, string body, string attachmentPath, bool deleteFile = false)
{
Task.Factory.StartNew(() =>
{
SendEmailAsync(toEmail, title, body, attachmentPath, deleteFile);
});
}
private async void SendEmailAsync(string toEmail, string title, string body, string attachmentPath, bool deleteFile)
{
Attachment attachment = null;
try
{
// class to hold all values from the section system.net/mailSettings/smtp in app.config
MailConfiguration smtpSection = new MailConfiguration();
using (MailMessage mailMsg = new MailMessage("<" + smtpSection.FromAddress + ">", toEmail))
{
mailMsg.IsBodyHtml = true;
mailMsg.Subject = title;
mailMsg.SubjectEncoding = Encoding.UTF8;
mailMsg.Body = body;
mailMsg.BodyEncoding = Encoding.UTF8;
if (!string.IsNullOrWhiteSpace(attachmentPath) && File.Exists(attachmentPath))
{
attachment = new Attachment(attachmentPath);
mailMsg.Attachments.Add(attachment);
}
using (SmtpClient smtpClient = new SmtpClient())
{
smtpClient.Timeout = 1000000;
smtpClient.UseDefaultCredentials = false;
if (deleteFile)
{
smtpClient.SendCompleted += (s, e) =>
{
attachment.Dispose();
File.Delete(attachmentPath);
};
}
await smtpClient.SendMailAsync(mailMsg);
}
}
}
catch (Exception ex)
{
Console.WriteLine("SendEmail exception: " + ex);
}
finally
{
Console.WriteLine("SendEmail done");
}
}
}
}
As discussed in the comments, there's no simple way to fix this while maintaining this same program structure. In particular, since you've currently got two ongoing email send calls with no knowledge of each other, there's no way to determine when it's safe to perform the delete. The second Send could finish first.
Changes I would make - I'd delete SendEmail and make SendEmailAsync public and Task returning. I'd also remove the concept of deleting after:
public async Task SendEmailAsync(string toEmail, string title, string body, string attachmentPath)
{
try
{
// class to hold all values from the section system.net/mailSettings/smtp in app.config
MailConfiguration smtpSection = new MailConfiguration();
using (MailMessage mailMsg = new MailMessage("<" + smtpSection.FromAddress + ">", toEmail))
{
mailMsg.IsBodyHtml = true;
mailMsg.Subject = title;
mailMsg.SubjectEncoding = Encoding.UTF8;
mailMsg.Body = body;
mailMsg.BodyEncoding = Encoding.UTF8;
if (!string.IsNullOrWhiteSpace(attachmentPath) && File.Exists(attachmentPath))
{
Attachment attachment = new Attachment(attachmentPath);
mailMsg.Attachments.Add(attachment);
}
using (SmtpClient smtpClient = new SmtpClient())
{
smtpClient.Timeout = 1000000;
smtpClient.UseDefaultCredentials = false;
await smtpClient.SendMailAsync(mailMsg);
}
}
}
catch (Exception ex)
{
Console.WriteLine("SendEmail exception: " + ex);
}
finally
{
Console.WriteLine("SendEmail done");
}
}
I'd then change Main as follows:
static void Main(string[] args)
{
Sender mailSender = new Sender();
var send1 = mailSender.SendEmailAsync("myemail#gmail.com", "Async mail with attachment", "Async mail with attachment body goes here ...", filePath + "TestFile.txt");
var send2 = mailSender.SendEmailAsync("anotheremail#gmail.com.com", "Async mail with attachment", "Async mail with attachment body goes here ...", filePath + "TestFile.txt");
Task.WaitAll(send1,send2);
File.Delete(filePath + "TestFile.txt");
Console.WriteLine("Email sent successfully!!!");
Console.ReadLine();
}
If this wasn't Main/if you're using bleeding-edge C#, I'd make it async also and use a couple of awaits at the current point I've got the WaitAll. It's the earliest piece of code common to both sends and so the only piece of code that can actually determine when it's safe to perform the delete.

Send email using Html template with MailKit in .net core application

I am sending an email from .net core application using MailKit, and it will sent it successfully.
But I want to use HTML template to send email with MailKit in .Net core.
Here are the code currently sending email with static body part
var emailMessage = new MimeMessage();
if (!string.IsNullOrWhiteSpace(cc))
{
emailMessage.Cc.Add(new MailboxAddress(cc));
}
else if (!string.IsNullOrWhiteSpace(EmailUserNameCC))
{
emailMessage.Cc.Add(new MailboxAddress(EmailUserNameCC));
}
if (!string.IsNullOrWhiteSpace(EmailUserNameBCC))
{
emailMessage.Bcc.Add(new MailboxAddress(EmailUserNameBCC));
}
emailMessage.From.Add(new MailboxAddress(mailFrom));
emailMessage.To.Add(new MailboxAddress(mailTo));
emailMessage.Subject = subject;
if (!string.IsNullOrWhiteSpace(replyTo))
{
emailMessage.InReplyTo = replyTo;
}
var builder = new BodyBuilder();// { TextBody = message };
builder.HtmlBody = message;
if (attachments != null && attachments.Count > 0)
{
foreach (var item in attachments)
{
builder.Attachments.Add(item.Key, item.Value);
}
builder.HtmlBody = builder.HtmlBody + " \n" + " PFA";
}
var multipart = new Multipart("mixed");
multipart.Add(new TextPart("html") { Text = message });
emailMessage.Body = builder.ToMessageBody();
using (var client = new SmtpClient())
{
var credentials = new NetworkCredential
{
UserName = EmailUserName,
Password = EmailPassword
};
if (!client.IsConnected)
{
client.Connect(SmtpHost, Convert.ToInt32(EmailHostPort));
client.Authenticate(EmailUserName, EmailPassword);
}
client.MessageSent += c_EmailReached;
client.Send(emailMessage);
}
Now, I want to use HTML template to replace body part.
So how can I use HTML Template with MailKit in .Net Core ?
Additional:
-> Also the special characters are not showing in actual email after sending email with html template. For some special characters it is displaying � . So how can I resolved this, to show special characters also.
Thanks.
You can use StreamReader to read the source file and assign it to your builder.HtmlBody.
using (StreamReader SourceReader = System.IO.File.OpenText(path to your file))
{
builder.HtmlBody = SourceReader.ReadToEnd();
}

Categories

Resources