I have run into a lot of issues over the years getting my website-generated emails delivered to inboxes. Unfairly marked as SPAM, accidentally blocked by ISP’s, and occasionally lost in space. This guide is a collection of what I’ve learned about sending emails from PHP. I’m going to keep this entry updated as I learn more tips.
I use PHPMailer which allows me to send emails by signing into the SMTP account/server (if you tell it to). I also have more control over headers, etc, with PHPMailer. When I switched to using PHPMailer/SMTP I noticed my messages not being marked as SPAM with certain email providers.
Send From Dedicated IP
Make sure your SMTP server does not share an IP address with others. If you host in a shared environment you’re out of luck. Even some dedicated server environments share an SMTP server (my old environment did, and I left). If your neighbor sends spam from the same server that you use for outgoing mail, your mail will likely be marked as SPAM, or worse, not delivered at all. Sometimes this lasts 24 hours, sometimes longer. Few businesses can risk not having their emails delivered.
Add DNS Entries
Email servers will check your DNS entries to make sure your outgoing IP is allowed to send mail for the domain.
- Reverse DNS (rDNS / PTR) record - Standard DNS resolves a domain name to an IP address. Reverse DNS resolves an IP address to a domain name. It says, OK 188.8.131.52, what’s your domain name? This is used to help determine the origin of the message and whether it matches the sending domain/address.
- SPF (Sender Policy Framework) record – The idea behind an SPF record is for your domain server to be able to be queried and asked for a list of email servers that are allowed to send email for your domain. Even if you’re sending emails from the same server IP address, it helps to project to the email servers out there that your emails are allowed to be created from this IP address for your domain name.
- DomainKeys and/or DKIM – Don’t be confused (by the Internet), these are two different, but similar, technologies DomainKeys and DKIM work in a public-key scenario, so a key is sent in the email that can be verified by querying the DNS server. Google it, or contact your webhost to find out how to set this up. It will be a combination of server settings and DNS entries. I was able to set up DomainKeys via Plesk but have not been able to figure out setting up DKIM.
Make sure your HELO, in the email header, does not show a different domain than the sending server. In my case, and maybe this is always true, when I finally got the HELO setup correctly the HELO message disappeared from the header, as it was no longer was needed. In my configuration I had to setup the HELO to match the sending server name which is not the domain of the email address. I set this in the PHPMailer config settings for HELO.
Odd SPAM Filters
- Even if you’re sending mail from a do-not-reply address, you need to have a return address in the email headers. Many email hosts will not deliver mail that does not have a reply to address.
- Do not obfuscate your HTML. Make sure it isn’t obvious that you created your HTML in code (one long line, etc).
- Be careful with images. In one instance the occurrence of a simple logo at the top of outgoing emails led GMail to send the emails to the SPAM folder. Avoid them unless you need them.
- Don’t use words like “100% guaranteed”, “as seen”, or an all caps subject.
- Look through SpamAssassin header rule codes to learn more.
Handle Bounced AND Rejected Emails
- Bounced – Some mail will be bounced back to you at a later time/date. Set up VERP for outgoing emails. This will mean adding a header of “return-path” to outgoing emails that includes the receiving email address in a specially formatted string. This string appears to be an email address at your domain but in reality routes to your catch-all email box. Then, you have your server set to pipe all mail to the catch-all box to a PHP script. The special string looks like firstname.lastname@example.org. You can parse this string and discover what address you emailed that bounced back. In PHPMailer I had to modify the code to allow for a new property called “returnpath” and I modified the code where PHPMailer sets the returnpath header value. Email me for more info.
- Rejected – Some mail will fail to send immediately, but PHPMailer won’t know this (for whatever reason). Since your MTA will email you a rejection notice, have all of your email sent to your do-not-reply address piped to the same script. When your MTA sends you a failed delivery notice you will want to process this message and add the email address to your do-not-email database table.
- Here is a link to my php email bounce script. I found this online and modified it over the years.
Sign up for Feedback Loops
The major mail providers and ISPs offer a feedback loop. Feedback loops allow the mail providers to alert you when a user reports your messages as SPAM. You can then act accordingly (stop emailing them?). Here is a list of some of the available feedback loops.