The root cause of this is that PHP's mail function is broken by design. Instead of parameterized values for everything, it passes the entirety of the "additional" options, which includes the from address, as one string for the shell to parse. If the flags were pulled out to individual options to be passed to the command instead, it wouldn't be possible to exploit things in the way it does. So, instead of:
mail ( string $to , string $subject , string $message [, string $additional_headers [, string $additional_parameters ]] )
it would be something like: mail ( string $to , string $subject , string $message [string $additional_headers], [string $additional_parameter, string $parameter values ] )
With the result passed to sendmail via the underlying functions, not relying on the shell to separate options for you. Any sort of user-supplied data should be parameterized and treated differently than data you provide. We've mostly learned our lessons from SQL injection, the rest of the stack still has a problem.