adding this line fixes the issue
Yes it does. Here's why, if the answer is of any value to anyone.
fopen() "binds a named resource, specified by filename, to a stream". If you read further down that page to the "Return Value" section, you'll note that fopen "Returns a file pointer resource on success, or FALSE on error."
mail() expects an address (string $to) in argument one. If you put your original $file (which is a named resource) there, you're putting a resource where a string is expected, and that's the reason for the error about conversion (unless the resources returns FALSE, in which case you'd probably get a slightly different error).
fgets() "gets (a) line from file pointer", so using it before the mail() call provides mail with a line from the file, which is a string, which therefore works because mail() is looking for a string.
There are a few ways to skin this cat. In your particular case, I'd probably have used file() to put my file_contents into an array instead:
$emails = file('emails.txt');
foreach ($emails as $to) {
mail($to, 'Thanks for joining!', Hi\nWe are glad to see you onboard\n\nPrivateloader);
echo "$to - just received a email.<br>";
}
I'd also recommend looking at file_get_contents() and file_put_contents() also, as they magically do most of the heavy fopen/fgets/fputs/fclose stuff for you.