2

So there are some great examples on the net of how to use Mailkit to send an email via SMTP.

Typically ending with :

client.Authenticate(theSMTPUsername,theSMTPPassword);
client.Send(emailMessage);
client.Disconnect(true);

However this is no good if async is needed :

client.Authenticate(theSMTPUsername,theSMTPPassword);
client.SendAsync(emailMessage);
client.Disconnect(true);

However, what I would like to know is when an async Send has completed, or if it does not succeed. Under .Net native libraries this is achieved with a callback (event handler).

Is it possible to define a 'Completed' callback handler for a MailKit SendAsync, and if not what is best practise to discover if it succeeded or not.

Thanks

Hughgo
  • 1,319
  • 5
  • 17
  • 26

1 Answers1

7

You don't want to have code like this:

client.Authenticate(theSMTPUsername,theSMTPPassword);
client.SendAsync(emailMessage);
client.Disconnect(true);

This will disconnect before the async send operation completes.

Instead, you want to do this:

client.Authenticate(theSMTPUsername,theSMTPPassword);
await client.SendAsync(emailMessage);
client.Disconnect(true);

Of course, once you await an async task... now you don't need a Completed event :)

That said, there is a MessageSent event that you can connect to:

http://www.mimekit.org/docs/html/E_MailKit_MailTransport_MessageSent.htm

jstedfast
  • 35,744
  • 5
  • 97
  • 110
  • Thanks for the steer. Await is nicer that a callback. – Hughgo Aug 25 '16 at 08:33
  • Looking a bit closer at this, I am not convinced that solution will work. Awaiting an asynchronous call will only wait for the Async part to return. This will not wait for the message to be sent. The code above could race, and disconnect before the work is done. A better way of doing it would be to Await the *synchronous* APIs. This ensures that each stage is done before proceeding. – Hughgo Aug 29 '16 at 08:02
  • When `client.Send()` returns, the message will have been sent. Likewise, when control resumes after `await client.SendAsync()`, the message will have been sent. There will be no race. You cannot `await` synchronous API's. – jstedfast Aug 29 '16 at 12:22
  • Yeah I agree awaiting synchronous APIs achieves nothing that calling the synchronous API would achieve on its own. But awaiting an async API does not necessarily mean that it will wait for the operation to complete - that depends on the implementation of the API - Await only waits until the called routine completes - not the operation which that routine asynchronously triggers. – Hughgo Aug 30 '16 at 09:16
  • Then look at the source code for MailKit to see what it does :) – jstedfast Aug 30 '16 at 10:54
  • I can see that recently the implementation was async wrapping sync operations which explains why 'await async' would work in this case. https://github.com/jstedfast/MailKit/issues/189 Not a nice way of doing things though. – Hughgo Aug 31 '16 at 07:06
  • `await async` would work regardless. The `await` means that the code should wait for the async task to complete. I.e., wait for it to finish sending a message. Even if the code was async due to `Stream.ReadAsync()/WriteAsync()`, it would have the same result: when the `await` returned, the message will have been sent. – jstedfast Aug 31 '16 at 12:44