As far as I can tell, PHP doesn't have any way to spawn a subprocess without passing it to /bin/sh for evaluation.
PHPMailer (not core php) apparently either calls php's popen(), which passes to the shell...or calls php's mail(), which uses popen(). There are other options in php, like proc_open(), but they also call /bin/sh.
TLDR: There isn't any way in PHP to avoid "relying on the shell to separate options for you".