By doing this you are not limiting the queue to the size of 1. If you have N producers, you can have more than N elements in the queue, but the idea is that each producer can only enter them one by one, with the agreement of the consumer. Nothing would stop the consumer from accepting a thousand of them before waiting before replying, therefore slowing down the producer. The idea is just to limit the rate at which you accept queries by tying it to the speed of the consumer.
If this is not enough, you can look at things like the jobs tool (https://github.com/esl/jobs) to work with scheduling.
By the way, you're mistaken on the idea of message sending always succeeding. The idea is that you will never error out because of trying to send a message (send and pray), not that the message will make it to destination. If you want any guarantee that the message made it, then you need that acknowledgement async message being sent back to you.
(you can make a data structure which makes memory explode, for instance lists:seq(1, 123456789123456), you can make a program which makes memory explode, for instance by growing the stack enough. Why is a message queue special?)
What happens if the message you can't add is a specific system message that allows the suspension of OTP processes for a code upgrade? Do you end up livelocked? How do you propagate back that you couldn't insert your element in the queue? Do you make message passing an operation that can fail? How would that work over the network when the message telling you something failed is lost over a netsplit? Is it a different kind of failure?
This has very deep design repercussions on the language. It's not impossible, but it wouldn't let Erlang be the same.