Reputation: 2286
i have a webApi setup (WebApi2). One of the requirements of the post method is (depending on some variables) send 2 emails.
I don't want the client to have to wait for the emails to be sent. I want them to just make the request and move on.
So I supposed that I should be using smtpClient.SendAsync but I keep getting http 500 internal error on the client - a c# winforms app
Works fine when I use normal smtpClient.Send. but not SendAsync. And I can't seem to catch the error on the server to locate the problem - drives me a bit dilly, and the error doesn't help. I can only assume its due to sending the email through incorrectly
Sample code as follows
//Web api code
private MessageDto _messageDto = null;
public void PostAddinObject(AddinObject newObject)
{
_messageDto = new MessageDto();
_messageDto.Email = "[email protected]";
..do dome otherstuff
SendMail("Hello Dot");
SendMail("Hello Peg");
..finish up and leave
}
private void SendMail(String msg)
{
using (var message = new MailMessage())
{
message.To.Add(_messageDto.Email);
message.Subject = "Hello;
message.Body = msg
try
{
Attachment datAttachment = new Attachment(_pdfFilePath, MediaTypeNames.Application.Pdf); //gets the pdf file from somewhere special
ContentDisposition disposition = datAttachment.ContentDisposition;
disposition.CreationDate = File.GetCreationTime(_pdfFilePath);
disposition.ModificationDate = File.GetLastWriteTime(_pdfFilePath);
disposition.ReadDate = File.GetLastAccessTime(_pdfFilePath);
message.Attachments.Add(datAttachment);
}
catch (Exception exception)
{
throw;
}
var smtpClient = new SmtpClient();
smtpClient.SendCompleted += new SendCompletedEventHandler(OnSendCompletedCallback);
smtpClient.SendAsync(message, null);
}
}
winforms code:
HttpClient _client=new HttpClient();
var response = _client.PostAsJsonAsync("api/Addin", newObject).Result;
Upvotes: 0
Views: 2646
Reputation: 34800
You can use Task.WhenAll
to await
multiple tasks. The will ensure the first email will not block the second. In the example below the request takes approx 3 seconds to complete (note the Task.Delay
in the SendEmail
method).
public async Task Post()
{
await Task.WhenAll(
SendEmail("[email protected]"),
SendEmail("[email protected]")
);
}
private async Task SendEmail(string to)
{
using (var client = new SmtpClient())
{
await Task.Delay(3000);
await client.SendMailAsync(
new MailMessage("[email protected]", to, "Test", "Test"));
}
}
You stated:
I want them to just make the request and move on.
Strictly speaking the above still makes the client wait for a response, it's just more efficient that what you were doing before.
If you want to "fire and forget" then the recommended approach is to add the emails to a queue/database and use a background process/service to actually send the emails.
That said, it is possible to just fire off the work on a background thread but you should tread carefully here and make sure you add proper exception handling:
public void Post()
{
Task.Factory.StartNew(() =>
{
SendEmail("[email protected]");
SendEmail("[email protected]");
});
}
This will return immediately rather than waiting for the emails to be sent. This also means you can't really give your client any indication of success.
Upvotes: 3
Reputation: 16328
From the documentation:
After calling SendAsync, you must wait for the e-mail transmission to complete before attempting to send another e-mail message using Send or SendAsync.
Also, I'd make sure the SmtpClient
object does not get destroyed before the e-mail has been sent. Your code does not provide that guarantee.
Upvotes: 0