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

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.

Related

How to send existing email from shared mailbox to other email address using graph API c#

How to send existing email from inbox to other email address using graph API c#
I have tried sending the existing email but Im not able to send it.
It is throwing error -Code: generalException Message: Unexpected exception returned from the service.
Below is the code snippet:
internal static async Task<System.Collections.Generic.IEnumerable<Message>> Sendemail(List<MM_Mailbox_Forward> toAddress, string smptpadd)
{
string from ="xyz#gmail.com"``your text``
var Toptenmessages1 = graphClient.Users["xyz#gmail.com"].MailFolders["Inbox"].Messages.Request().Top(1);
var task = System.Threading.Tasks.Task.Run(async () => await Toptenmessages1.GetAsync());
var authResult2 = task.Result;
foreach (var message in authResult2)
{
try
{
var messages = new Message
{
Subject = message.Subject,
Body = message.Body,
ToRecipients = new List<Recipient>()
{
new Recipient
{
EmailAddress = new EmailAddress
{
Address = "abc#gmail.com"
}
}
},
};
await graphClient
.Users[from]
.SendMail(messages, true)
.Request()
.PostAsync();
}
}
catch (Exception ex)
{
Console.WriteLine("error:" + ex);
}
Make sure you are not using a shared email box, you can't (by default) send email with a shared email box.

Sending Email Using SendGrid

I'm trying to send email from sendgrid as follows-
public static async Task<int> SendEmail(string fromEmail, string toEmail, string emailMessage, string subject)
{
try
{
// Create the email object first, then add the properties.
var myMessage = new SendGridMessage();
// Add the message properties.
myMessage.AddTo(toEmail);
myMessage.From = new MailAddress(fromEmail);
myMessage.Subject = subject;
myMessage.Html = emailMessage;
var username = ConfigurationManager.AppSettings["NetworkUserId"];
var pswd = ConfigurationManager.AppSettings["NetworkUserPwd"];
var domain = ConfigurationManager.AppSettings["HostName"];
// Create credentials, specifying your user name and password.
var credentials = new NetworkCredential(username, pswd, domain);
// Create an Web transport for sending email.
var transportWeb = new Web(credentials);
if (transportWeb != null)
await transportWeb.DeliverAsync(myMessage);
else
{
await Task.FromResult(0);
}
}
catch (System.Exception ex)
{
//throw ex;
}
return 1;
}
Here I'm using async and await, I got mail successfully but I'm expecting return value as 1. I think my debugger hitch into await.
You do not need to await the result of 0, your code should be:
public static async Task<int> SendEmail(string fromEmail, string toEmail, string emailMessage, string subject) {
try {
// Same as your example
if (transportWeb != null)
await transportWeb.DeliverAsync("");
else {
return 0;
}
}
catch (System.Exception ex) {
//throw ex;
}
return 1;
}

IOException: The process cannot access the file because it is being used by another process

I'm trying to send an email with attachment when I access an action of ASP.NET Core controller. The attachment is downloaded by a site that exports an html page to pdf. The function sends the email but it can't delete the attachment file because it is still used by another process.
Where is the mistake?
public void SendAsHtml(string body, string subject, string emailTo, string url = null, string fileName = null)
{
string path = null;
using (SmtpClient client = GetSmtpClient())
{
MailMessage mailMessage = new MailMessage
{
From = new MailAddress(sendemail),
Body = body,
Subject = subject,
IsBodyHtml = true
};
mailMessage.To.Add(emailTo);
if (url != null)
{
if (fileName == null)
{
fileName = DateTime.Now.ToString("yyyyMMddHHmmss.pdf");
}
if (!fileName.EndsWith(".pdf"))
{
fileName += ".pdf";
}
path = #"c:\temp\" + fileName;
DeleteFile(path);
using (WebClient myWebClient = new WebClient())
{
myWebClient.DownloadFile($"{htmlToPdfServer}?url=" + url, path);
}
Attachment attachment = new Attachment(path);
mailMessage.Attachments.Add(attachment);
}
client.Send(mailMessage);
}
if (path != null)
{
// it does not work
DeleteFile(path);
}
}
private static void DeleteFile(string path)
{
try
{
if (File.Exists(path))
{
File.Delete(path);
}
}
catch (Exception ex)
{
Log.Warning($"Send email service: cannot delete file {path} {ex.Message}");
}
}
You should try calling attachment.Dispose() after sending the mail message.
To do this, declare Attachment attachment; before if (url != null) and call Dispose() after client.Send(mailMessage); if attachment != null.

Sending email via AWS Lambda with SES into C#

I have created one AWS Lambda function using Visual Studio and C# with .net core1.0
I have to send an email after doing some operation on my Lambda function.
My code is as below. taken from AWS Doc
using Amazon.DynamoDBv2;
using Amazon.DynamoDBv2.Model;
using Amazon.Lambda.Core;
using System;
using System.Collections.Generic;
using Amazon.SimpleEmail;
using Amazon.SimpleEmail.Model;
using Amazon;
namespace MyProject
{
public class AddAlarms
{
private static AmazonDynamoDBClient client = new AmazonDynamoDBClient();
public string AddAlarmsHandler(GetUserAlerts input, ILambdaContext context)
{
var client = new AmazonSimpleEmailServiceClient(RegionEndpoint.USEast1);
List<string> toAddress = new List<string>();
toAddress.Add("ToEmail#domain.com");
var sendRequest = new SendEmailRequest
{
Source = "sourceEmail#domain.com",
Destination = new Destination
{
ToAddresses = toAddress
},
Message = new Message
{
Subject = new Content("Subject of email"),
Body = new Body
{
Html = new Content
{
Charset = "UTF-8",
Data = "Hello Email, HTML Body"
},
Text = new Content
{
Charset = "UTF-8",
Data = "Hello email, Text Body"
}
}
},
ConfigurationSetName = "ConfigSet"
};
string returnval = string.Empty;
try
{
Console.WriteLine("Sending email using Amazon SES...");
returnval += "Sending email using Amazon SES...";
var response = client.SendEmailAsync(sendRequest);
System.Threading.Thread.Sleep(5000);
returnval += ", Response Status - " + response.Status.ToString() + " - ";
Console.WriteLine("The email was sent successfully.");
returnval += "The email was sent successfully.....";
}
catch (Exception ex)
{
returnval += "The email was not sent.";
Console.WriteLine("The email was not sent.");
returnval += "Error message: " + ex.Message;
Console.WriteLine("Error message: " + ex.Message);
}
return returnval;
}
}
}
so Lambda function created successfully and it shows in section of Lambda into AWS
so while testing this function i get response that after sending - "Faulted"
and email not received by receiver.
I have verified both email TO and FROM into email verification of AWS SES.
I get one Node.Js code which runs successfully and also receiving email and node.js code i have taken from link
I have checked ROLE and using same role for Node.Js code and works fine, but for C# lambda function i am getting response "Faulted".
Please help to solve this problem in AWS Lambda

file in use after sending email with attachment

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;

Categories

Resources