I have a button that - when the user clicks it - sends an email. I'd love for this to just return immediately and send the email in the background without holding up the UI as the email is processed. I've searched around for async
/await
/etc and I've found so many different approaches - I'm looking for a simple solution to this. My email code:
public void SendEmail(string toAddress, string subject, string body, string code = null) {
try {
var fromAddressObj = new MailAddress("[email protected]", "Name");
var toAddressObj = new MailAddress(toAddress, toAddress);
const string fromPassword = "Password";
var smtp = new SmtpClient {
Host = "smtp.office365.com",
Port = 587,
EnableSsl = true,
DeliveryMethod = SmtpDeliveryMethod.Network,
UseDefaultCredentials = false,
Credentials = new NetworkCredential(fromAddressObj.Address, fromPassword)
};
using (var message = new MailMessage(fromAddressObj, toAddressObj) {
Subject = subject,
IsBodyHtml = true
}) {
message.Body = body;
smtp.Send(message);
}
} catch (Exception e) {
Elmah.ErrorSignal.FromCurrentContext().Raise(e);
}
}
How can I modify this so that the caller is not blocked?
SmtpClient
has SendMailAsync
so using it instead of Send
will unblock the UI thread while sending but you can still handle any exception that may occur:
private async void button_Click(object sender, EventArgs e)
{
await SendEmailAsync(address, subject, body)
}
public async Task SendEmailAsync(string toAddress, string subject, string body, string code = null)
{
try
{
var fromAddressObj = new MailAddress("[email protected]", "Name");
var toAddressObj = new MailAddress(toAddress, toAddress);
const string fromPassword = "Password";
var smtp = new SmtpClient {
Host = "smtp.office365.com",
Port = 587,
EnableSsl = true,
DeliveryMethod = SmtpDeliveryMethod.Network,
UseDefaultCredentials = false,
Credentials = new NetworkCredential(fromAddressObj.Address, fromPassword)
};
using (var message = new MailMessage(fromAddressObj, toAddressObj)
{
Subject = subject,
IsBodyHtml = true
})
{
message.Body = body;
await smtp.SendMailAsync(message);
}
}
catch (Exception e)
{
Elmah.ErrorSignal.FromCurrentContext().Raise(e);
}
}
If the synchronous part of the async
method (the part before the await
) still manages to block the UI thread you can offload it to a ThreadPool
thread:
private async void button_Click(object sender, EventArgs e)
{
await Task.Run(() => SendEmailAsync(address, subject, body))
}
Notes:
Task
without await
ing it unless you're in a situation where you can't use await
(a UI event handler is not one of those cases)async void
is only appropriate for UI event handlers. Don't use it anywhere else.You could run your method in a task and not wait for it:
private void button_Click(object sender, EventArgs e)
{
Task.Run( () => SendEMail(address, subject, body) );
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With