Normally you don't expect a direct reply when sending a cast, otherwise you would use gen_server:call.
A real world example, I have a gen_server that handles some "channels" and there is lots of use to append the channel name to error logging. The channel name is stored in the state of the gen_server. In order not to hold up the process who wants to log an error I don't use a "get name" synchronous call to get the name an prepend but send the messages with casts:
error(Pid, Tags) ->
gen_server:cast(Pid, {log, error_report, Tags}).
warning(Pid, Tags) ->
gen_server:cast(Pid, {log, warning_report, Tags}).
info(Pid, Tags) ->
gen_server:cast(Pid, {log, info_report, Tags}).
The cast is handled in a quite simple handler, that does not return.
handle_cast({log, Report, Tags}, #state{name=Name}=State) ->
error_logger:Report([{chan, Name} | Tags]),
{noreply, State};
If you have asynchronous messages to send back, this is totally independent of the handling of the cast. You somehow need to know where to send these messages which you have to store in the State
somehow, or you are using a fixed name.
Normally you shouldn't just send a message but rather call a function of the receiving process module (which just might be another cast or plain message sending).