Recently, I learned something new about one of the oldest technologies I regularly use – email. Once you get beyond putting a simple plain text email together for sending from a web app, email can get pretty complicated. Sending things in multiple formats (such as HTML with a plain text fall-back), sending attachments, using different encodings and so on, generally there’s quite a lot to know about mail.
One thing I didn’t really know much about was the SMTP envelope. Whilst the mail has a set of headers indicating the subject, who it’s from and who it’s to, the envelope that surrounds that mail has a bunch of headers too. It was these envelope headers that were causing me an issue on one site I run.
I had a message forwarded from a rather irate user who was complaining that he wasn’t receiving our emails because our server was sending from an invalid email address. He had his mail server configured to reject any email sent from an invalid address (I guess to combat spam) and so was rejecting our mails when they got to him. I was sending using PHP’s mail() function, and was dutifully setting the From: header to a valid address, so at first didn’t get what was going on.
Turns out the problem was with the From address on the envelope, and not in the message headers themselves. PHP’s mail() function uses Sendmail to, well, send mail. On being given a message to send that has no explicit envelope From address set, Sendmail will make up an address of current-user@server-name. If you’re lucky this might coincide with a real email address, but in a lot of cases it won’t. This was the circumstance I was coming up against, and the reason our emails weren’t getting through.
Turns out (via a very helpful comment on the php.net page for mail()) that lesser-spotted fifth argument to mail() can be used to send an additional parameter to Sendmail to set the envelope From address. "-r from@example.com"
For good measure, you should also set the Return-Path header on the mail (typically to the same address), as this is also sometimes checked for validity. I’ve been using PHP’s mail() function for years without knowing this, so I thought it was probably worth sharing.
I did a bit of spot checking in my mailbox of emails I’d recently received from other online services. This default current-user@server-name envelope address and Return-Path is incredibly common. I know Shaun uses PHP over at Mint, and his emails looked exactly like mine. (As an aside – I really recommend Mint. I use it on a couple of sites and it’s both inexpensive and full of awesomeness.)
Of course, it’s valid to question whether it’s wise to be rejecting email on the basis of a mistake is some obscure mail headers that perhaps not a lot of people know about. However, by the same reasoning, if I’m going to suggest people should be liberal in what they receive, I need to uphold my end of the bargain and be strict in what I send.



Comments
Every once in a while, we get a phone from our web hoster because one of the programmers forgot to use the Return-path. Especially with large websites he gets annoyed with the lots of blocked e-mail.
Glad to see you back on the blog Drew, I was getting worried about you. Now if I can get the php mail() function to stop sending emails from “nobody” I’d be happy.
Shouldn’t that be ”-f from@example.com”? Or is that a different option?
Different option – check the link to the comment on php.net.
Top notch advice! You can also use the ini_set function to set the default email address that PHP uses if you wish to go that way about matters. Either or though, no more irate customers! Or, well, that’s the theory.