The usual way this situation is dealt with is to have the transmit function return a 'future' (object) immediately, rather than blocking and returning the final result. The future object can have functions which return the final result in a blocking manner (like currently) or non-blocking manner which can be polled by the application.
Importantly, the reason I have raised this issue is simply that blocking on an unsuccessful transmit (esp. to a sleeping end device, which could take quite some time), is really not great when any kind of user interface is also being managed. For example, simply flashing an LED should be simple but can't be done properly if a message must be transmitted from time to time.
There are other consequences to the transmit call blocking... WDT for example continues running during transmit and can trip if its timeout isn't made longer than the transmit timeout (which could be very long for a sleeping end device).