GETTING YOUR PHP BACKEND TO FINALLY SEND EMAIL
You’re developing a back-end in PHP (Laravel, Lumen, or just freewheeling it) and you want it to send out email when users use your “forgot password” functionality. Getting everything configured just right can be a headache and this article lists all the things you need to do. You could also reach for a third-party solution, but then you’d have to have your credit card handy.
Using a 3rd-party service?
If you don’t want to code the email sending yourself, you can reach for a third-party solution. Mailgun, Sendgrid and Mailchimp come to mind, but they all cost money. Mailgun has a free tier, but it’ll only work for sending out email to up to 5 known email addresses, and that’s not what you want - you want to send email out into the world (but only one email at a time). Even if you did pay for a third-party solution, it may have a free tier of up to, say, 1,000 emails per month, after which you start paying. God forbid that your API key falls into the wrong hands and someone sends out a million emails with it!
Using your own server
In my case, I have a shared-hosting server that runs PHP. Through CPanel, I am able to create email addresses, so I can go ahead and create info@myserver.org
and use that to send email from.
Problem 1: Email sent manually from my server does not arrive
With so many spammers around, email has become something like the Wild West. Anyone can send out emails, and users are bombarded with spam. To fight some of this, email providers try to block emails where it can’t be determined where the email came from - in which case it could be a spoofed address.
Sending out a simple email manually from my CPanel email client to a GMail address will result in this (I’ll get an email back from CPanel or from Gmail):
In other words, if your domain doesn’t have SPF and DKIM records, GMail (and likely others) will reject your mails straight out of the gate.
A solution is brought by CPanel itself: the Email deliverability option.
If you have no DKIM or SPF records setup, then the Email Deliverabilty screen will report that there is a problem and offer to repair it:
If your DNS is actually under CPanel’s control, you can CPanel create SPF and DKIM records automatically. If not, and like me, you have your domain at GoDaddy while you’re hosting somewhere else, it’s not going to be automatic. But never fear, CPanel can still help. If you choose the Manage option, CPanel will tell you that no DKIM record exists, and provide you with a suggested record:
This system does not control DNS for the “myserver.org” domain and the system did not find any authoritative nameservers for this domain. You can install the suggested “DKIM” record locally. However, this server is not the authoritative nameserver. If you install this record, this change will not be effective. Contact your domain registrar to verify this domain’s registration.
You can actually take these values to GoDaddy and create the DNS records yourself. Note that both need to be TXT records. Create these and save them, wait a few minutes, and then manually send an email again. It should now arrive without issue into a GMail inbox.
Getting Laravel’s mailer to behave
With the TXT records configured, I found that while I could send emails manually through the email web client and receive them, emails from PHP would not be received.
It turns out that for Lumen, after configuring all that’s necessary for Illuminate/mail
, no email would be sent. I also found that the email sending route returns rather quickly; ordinarily it would be processing a little while before returning.
I there checked my STMP settings using the GMass SMTP Test Tool which came in handy. I found that I was able to send email email through this and receive it in a GMail inbox, so my SMTP settings were correct. I also noted that sending the email took a few seconds, so it was suspicious that the Laravel code returned immediately.
Finding no way to get the Laravel code to tell me why it failed, I installed the venerable PHPMailer instead. Testing it out by pasting its sample code into my back-end implementation, it immediately worked.
Stepping away from Laravel’s SwiftMailer was made easier by using Laravel’s ENV
variables in PHPMailer instead of using hardcoded values (these are the settings from the .env
file):
Further, it’s still possible to use Laravel’s Blade templates by rendering them to string:
I know I’ve had Laravel’s SwiftMailer work for me in the past, but PHPMailer does me the courtesy of letting me put a try
…catch
around the mail sending process so that I’ll know when it’s failed. Also, a full SMTP debug can be echoed to the output to see precisely what went wrong.