Delivering email with PHP

February 21, 2011 in Web Development

TL;DR version: Email delivery is hard, getting through spam filters is hard. Use somebody else’s code and sign up for a transactional email service and make them send emails for you.

I’m not a very active user on Stack Overflow but I sometimes take 1-2 hours off and try to answer a few questions. I noticed recently how many questions come up on the topic of sending email with web forms, often related to PHP. So I decided to write up a small post on what I would say is the best method to send email using PHP.

Delivering email is hard – they’ll think you’re a spam!

Just being able to send an email is not a problem at all. It takes a single line of code (often times) and the mail is off. However, getting that email to the recipient’s inbox is harder, mostly due to spam-filtering and other spam fighting mechanisms designed to keep spam away. Spam filters are only half the story. Email servers utilize multiple automated techniques to find and detect spam these days.

Network
Creative Commons License credit: Claus Rebler

Most common methods used by servers to keep spam away:

  1. First there’s the spam filters. They use all kinds of methods, strictly on the email messages themselves to detect if that email is a proper one. Besides doing assumptions based on statistical analysis of the word usage in the email, they also check for various headers and the general “fingerprint” of the email.
  2. Server black-lists. A lot of mail servers have a subscription to databases that list IPs of servers that have been know to send out spam. If your server gets listed in one of those databases, you’ll have to ask for a delisting and that can become pretty hard.
  3. Challenge-response. This method revolves around asking the sender to pass various tests to prove his authenticity. The most common one being checking to see if the sending email address exists, but this gets more complicated. More info on challenge-response systems.
  4. Reverse DNS checking. This involves doing a reverse DNS lookup for certain things, mostly to disallow email sent from dial-up users and other homes, but there is more to it.

This is by no means a comprehensive list. There are many many many more issues to think of when you want to do email right and the Wikipedia entry about anti-spam techniques servers use has a very good list of all there is to think about.

The difficulty level

Now, given the difficulty level and the techniques we’re up against, you should really know what you’re doing if you want to do this yourself.

“But I’m not sending spam, my email is legitimate.”

That may be true, but the spammers out there have gone to such lengths to make their emails seem real (from a technical perspective) that you’re up against a tough competition if you want your emails to get through.

You might even realize that your emails are being delivered, say, 90% of the time, even 95%. Those are still a lot of inboxes that are not getting your emails. On top of that you’ll have server configuration options, queue problems, getting delisted, etc.

Doing it yourself with the mail() function

PHP provides a built-in generic email function called mail(). It accepts 3 required parameters (to, subject and message) and two optional ones (headers and additional parameters). Here’s an example:

Note: A lot of people don’t like my indentation style, but I think it’s more readable like this, rather than having multiple parameters in a single long line.

If you want to do it with a proper “from” address and a reply to, you can do the following:

Now, both of these example are plain horrible. You will hardly get any email delivered that way. There are things missing in the headers and your email will look like regular spam to the spam filtering software.

Send email using PHP Mailer or Swift mailer

What I always recommend to people when they ask me about this, is to use class/libarary called PHP mailer or Swift mailer. They’re used for the sole purpose of sending out emails and they get the job done better than you (or I) would ever using the mail() function ourselves. For the sake of this guide, I’ll be using PHP mailer, since it’s better known.

You can also use PHP Mailer to connect to SMTP servers easily, which will save you a lot of code. An SMTP server is a server running a piece of software that sends and receives emails for multiple users.

Here’s an example how you would connect to an SMTP server and send a similar email as before with PHP Mailer:

It also allows you to add attachments pretty easily. Here’s an example (working with our previous object)

I tried to comment the code extensively, so it should explain itself for the most part.

Using an email deliverability service or high quality SMTP

Creating the email itself is only half the story. You also need to get it out there and you need an SMTP server. Most hosting providers provide some sort of SMTP server, but you usually don’t have full access to them. If you’re using some VM hosting, that will probably also have restrictions in the EULA or the terms around how many emails you can send out, etc.

(And if you think you don’t need an SMTP server, you’re wrong. It may be that the web server running your website is sending the emails, but just know that then the web server itself is running an SMTP server.)

The really easy way out of this is to use an email deliverability service. Sometimes they’re called transactional email services. There are a few out there, the ones I know about are:

  • SendGrid – Great support, great dedication to delivery and they also have an API. www.sendgrid.com
  • PostmarkApp – www.postmarkapp.com
  • PostageApp – This is a relatively new service, so I don’t know much about them, but they seem to have fair prices - www.postageapp.com

They all have their price point, feature set, etc. I’m very fond of sendgrid.com. They are really doing things right in the marketing side and have grown a lot in a short time. They also offer a free plan if you only send a small amount of emails (200 email per day), which will cover the needs of most websites.

Sign up here for sendgrid: http://sendgrid.com/

Here’s how you plug sendgrid’s SMTP servers into our PHP mailer configuration. Note: You’ll need to have signed up for an account for it to work:

So what’s changed in our example? Almost nothing. Just the login information. It’s that simple.

SendGrid and most of the other transactional email services offer a very powerful API. SendGrid’s API can be used both for sending out the emails, checking for blocked addresses, receiving notifications and more. I don’t know the other services’ APIs but I expect similar functionality.

Conclusion

No fighting the email servers, tweaking MTA config files, no fighting the queue, no spam list delistings, etc. It’s a luxury when you don’t have to fight your server all the time. As you may hear, I have had my share of those fights in my day and I’m relieved that I’ll never have to do that again :)

So, what used to amount to a fair share of work, can now be done by a plugin in a library and plugging in a specialized web service. Less code is better code.

If you’re interested in more code examples, tips or tricks around emails, etc, let me know in the comments.

  • http://www.mostlymaths.net Ruben Berenguel

    I don’t think I’ll be emailing soon (and least in PHP, I only know how to read the code more or less), but I’ll bookmark this, just in case. I knew the problems of self-sending mail, but not the solutions. Now I know them ;)

    Cheers,

    Ruben

    • http://arnorhs.com/ arnorhs

      Hope it can help at one point :-)

  • http://www.poimart.com siddharth

    Hi…
    I am trying to use the phpmailer to send mail. But when I send mail it getting delivered as spam. I want it to get it delivered into inbox.

    I set the smtp authentication but its not taking it..:-(
    What can be done..????
    Any solutions for it..??


    regards
    Sid

  • http://arnorhs.com/ arnorhs

    @siddharth There are many things that the spam filters evaluate to decide if an email is spam or not. Beyond the scope of the email itself from a technological standpoint, the text (copy) of the email can play a big role.

    It’s hard for me to tell why without seeing the actual email, but these are the first things I would check:

    1. Check if your outgoing mail server’s IP address in a spam blacklist, eg. by using this site: http://www.dnsbl.info/dnsbl-database-check.php

    You’ll have to know your outgoing mail server’s IP address.

    2. What software is giving the email a spam grade? If it’s Outlook it’s spam software is horribly prone to false positives.
    If it’s gmail’s, I’d be actually pretty surprised because theirs is pretty good.
    If it’s spam assassin (probably if using some normal hosting provider) you can actually get a report from the hosting provider and information about what triggered the spam grade. This can help a lot.

  • Todd

    Great tutorial. I was looking for something with Sendgrid in and this is perfect.
    Thanks! Todd

  • Guillaume Lambert

    Old article but still relevant.

    Just one thing, change the $mail->port to 587 :)

  • Matt Rodriguez

    Our smtp server is Sendgrid and email library is PHPMailer. Any way I can apply a Sendgrid bypass_list_management filter inside my PHPMailer code? If we are using the Sendgrid library, then there is a filter I can apply, but I’m not sure how to apply a filter while using the PHPMailer library. Any thoughts?