Exactly once delivery

Question about transactions:
Is “exactly once delivery” guaranteed if we use SqlServer transport and TransportTransactionMode.SendsAtomicWithReceive ?
and does that work for Azure service bus as a transport as well?

one endpoint will be sending an email to the client so we don’t want to spam the customer.


Hi Robert,

It does not guarantee exactly once delivery. All it does is guarantee transactional consistency between incoming and outgoing messages.

When you’re using the SQL Transport you can think of a message receieve operation as a SQL DELETE statement, and message send operations as INSERT statements. SendsAtomicWithReceieve guarantees that those statements are in the same transaction. Either the incoming message is receieved (deleted) and all outgoing messages are sent (inserted), or nothing is deleted/inserted.

What it does not guarantee is the transactional consistency of any resource outside of the transport. This is a problem for something like sending an email via an SMTP server. Under normal conditions, this is what processing the message is going to look like.

  1. Open transaction
  2. Receive (DELETE) message
  3. Send email details to SMTP server
  4. Receive confirmation from SMTP server that email is sent
  5. Commit transaction from (1)

At this point, everything is great. The email has been sent and the mesage has been consumed (deleted) so we can’t send the same email (or process the same message) again. What happens when something goes wrong at step 4?

If we don’t get a confirmation back from the SMTP server then the request we made at step 3 will eventually time out and throw an exception. In that case the following happens.

  1. Open transatcion
  2. Receieve (DELETE) message
  3. Send email details to SMTP server
  4. SMTP server did not respond, exception thrown
  5. Roll back transaction from (1)

At this point, the delete operation has been cancelled by rolling back the transaction, so the message is back in the input queue, ready to be processed again. Was the email sent or not? Unfortunately we don’t know.

As the SMTP server did not respond, we aren’t sure if it was down or if there was a temporary outage in the network. If the network is at fault, did our original request make it through and it’s only the response that got dropped or did the SMTP server never get our request? If the server crashed, did it crash before sending our email or afterwards? This is an example of the two generals problem.

Transactionality isn’t going to help here because the SMTP server isn’t going to participate in a transaction. The real question is, is it safe to retry?

If the business really cannot tolerate duplicate emails being sent then they need to accept the possibility that some emails will not go out. If you turn off delayed and immediate retries then the message will only be processed once and if it fails that once, then it will be forwarded to an error queue where it can be inspected and managed by operations staff to determine whether or not it is safe to retry.

Hopefully that helps.

Mike Minutillo
Particular Software

Even then a message may be processed multiple times if you have multiple copies of the endpoint running or if the endpoint crashes after rolling back the transaction but before forwarding the message to the error queue.