I am trying to send multiple messages using SendMailAsync and I am trying to pass a cancellation token to interrupt the sending process when the cancellation has been requested.
static void Send(SmtpClientFactory factory, IEnumerable<MailMessage> messages)
{
Task.WaitAll(SendAsync(factory, messages, CancellationToken.None));
}
static async Task SendAsync(SmtpClientFactory factory, IEnumerable<MailMessage> messages, CancellationToken token)
{
await Task.Run(async () =>
{
using (SmtpClient smtpClient = factory())
{
foreach (MailMessage message in messages)
{
await smtpClient.SendMailAsync(message).ConfigureAwait(false);
}
}
}, token);
}
When I use the non-async Send, it gets into a deadlock. How can I send my message synchrnously and use a cancellation token to cancel when the time is up?
You can combine CancellationToken.Register
and SmtpClient.SendAsyncCancel
to do what you need:
static async Task SendAsync(SmtpClientFactory factory, IEnumerable<MailMessage> messages, CancellationToken token)
{
await Task.Run(async () =>
{
using (SmtpClient smtpClient = factory())
{
foreach (MailMessage message in messages)
{
token.ThrowIfCancellationRequested();
using (token.Register(() => smtpClient.SendAsyncCancel()))
{
await smtpClient.SendMailAsync(message).ConfigureAwait(false);
}
}
}
}, token);
}
Keep in mind that SmtpClient
is officially deprecated:
SmtpClient and its network of types are poorly designed, we strongly recommend you use https://github.com/jstedfast/MailKit and https://github.com/jstedfast/MimeKit instead
Not only is MailKit threadsafe, but it's far more flexible in terms of message construction, and it supports CancellationToken
to boot!