Please tell me (preferably with examples) how append_variable_outputs and append_message_outputs differ, when they should be used, and what the argument that is passed to these functions depends on.
In short, if you’re sending coins to an Address via std::token::transfer_to_address (or any of the other library functions that wrap it), then you need append_variable_outputs. This is, by far, the most common use case.
Appending message outputs is only useful when sending messages via the smo opcode. This is handled by the methods in sway/message.sw at master · FuelLabs/sway · GitHub. Messages are mostly useful for sending arbitrary messages to a data layer (e.g. Fuel → Ethereum), so that’s a slightly more niche use case.
As for how many variable outputs you need to append, it depends on how many transfers you’re making to the Address from that particular contract method. You basically need as many variable outputs as you have transfers. The SDK does in fact have a utility that estimates all tx dependencies for you (such as variable outputs) and you should probably just use it. For example:
let _ = contract_methods
.estimate_tx_dependencies(None) // None means "no max attempts"