I occasionally get requests for a way to have an email sent automatically when a certain condition is met. For example, when it’s someone’s birthday, an email would be sent to them with a birthday greeting.
This kind of thing is possible using the WordPress cron, which can launch functions in the background.
This is a tutorial on how something like this can be set up, and requires the use of the Participants Database Email Expansion Kit, which provides a way to define email templates that can be used for any number of different purposes.
Before we get into this, I want to warn that this is not a tutorial for non-coders…you will definitely need to know php and mysql to get what you want out of this.
Please note: the line that actually sends emails has been commented out for safety. This plugin will not send email unless you un-comment line 81
In this tutorial, we will be using the example of sending a reminder to people to keep their record updated. It is a reminder that is sent out automatically if it has been over a month since the last time they updated their record.
This example is probably different from what you might want to do, but it has all the elements you will need for your own application. Any application that sends emails automatically will need these basic parts:
- Set up a WordPress cron event that will be triggered in the background at regular intervals.
- When the cron event is triggered, it lanches a function to check the database for records that should have an email sent.
- We also need to check if the email has already been sent, so we don’t send them an email every time the cron event is fired.
- Send the email: this is done by triggering an action in the Email Expansion Kit add-on for Participants Database
- Log the send so that the next time the cron action is triggered we know that an email was sent to that person.
The WordPress Cron
Generally, a cron is a scheduled action on a web server. WordPress has its own built-in cron where you can schedule events to recur at specific intervals such as hourly or daily. Our example runs every day to check for possible recipients of the reminder email. There’s no need to have it run more often because we don’t really care what time the email is sent, we just want it to be within a day of when the record becomes eligible to get a reminder sent.
Checking the Database
When the cron is triggered, the plugin needs to check the database to get a list of records that qualify for the reminder email.
This is one part you will be customizing for your own application. For example, for the birthday one, you’ll need a database query that will match all records with a birth date value that matches today’s date. (You will need to determine the query needed to get the records for whatever it is you want to do.)
In this example, we get all the records where the user has not updated their record in the last 30 days. This happens in the get_late_accounts method in the example code.
Preventing Duplicate Sends
Once someone has been reminded, we probably don’t want to remind them again for a while. We handle that by logging the date and time we sent an email to them. That way, we can know how long it’s been since the last time we sent the email.
This is handled in the email_should_be_sent method. First we check for any log entry for the record and return true if an email has never been sent.
Then we check the date of the last sent email to see if we need to send another one. If the date is outside our “don’t send” window, we return true, indicating that the record is ready for another email.
Sending the Email
Sending the email is relatively simple: we need to know which email template to use, and also send the data from the record so that the template values can be filled in with data from that record. We already have the record data from checking the database.
Sending the email is handled in the send_reminder method. We first get the template from the Email Expansion Kit plugin, then we trigger the action with the template and the record data.
Logging the Send
Whenever an email is sent, we save the date and time it was sent for the record. The next time we’re considering sending an email to this record, we can check the log to see when that happened last.
The PDB Email Cron Plugin
The plugin is pretty simple, it’s really just a demonstration of how to handle sending an email on a cron.
To use this plugin, you must first configure an email template. Leave the “Send Action” blank, we are using our own send trigger to send it, so it doesn’t need to have one programmed in.
After setting up your template, note the ID number of the template. You can see this on the page where the template is defined. You will type this number in to the $template_id variable declaration near the top of the example code.
Defining the Conditions of the Send
This part is going to be the most challenging part for less-experienced coders. You will need to come up with a database query that will select the records that you might want to send an email to.
In the example, in the get_late_accounts method, we first compute the threshold date…the date where if the record is older than that, it will be selected. That date is formatted as a mysql timestamp because we will be comparing against a mysql timestamp in the database record.
We run the query and get the set of matched records. Next, we loop through those records, checking for ones that need to actually have an email sent. Your custom application will probably need to do something like that as well.
Be Careful with Email Sending
Remember you could easily send lots of emails out unintentionally. This plugin has no throttling of any kind, so if it’s possible the plugin could send hundreds of emails, you will need to throttle that down so it doesn’t try to do that.
One way to throttle it would be to count how many emails are going out in a single session. Once a certain number is reached, stop sending. The remaining records will get their emails the next time around because the code will skip the ones that got it already. You will want to increase the frequency of the cron if you’re doing that so that all the emails will eventually go out in a reasonable time.
Testing the Plugin
Be sure to test things without actually sending emails until you know it’s working as expected. Nobody wants to get a bunch of spurious “test” emails. I commented out the line that sends the email in the send_reminder method.
You should add an error_log statement that tells you that an email would be sent. I put an example of that in comments in the code. When the cron runs, the error log will show you which records would get emails sent to them.
It’s a good idea to install a plugin to help with crons, I use WP Crontrol. It lets you see which crons are scheduled, and more importantly lets you trigger a cron manually. This is a good way to test your plugin because you don’t have to wait for it to trigger on it’s own.
Get your php error log set up or Participants Database debugging. You can put error_log statements in the code to see how it is executing and if you’re getting the expected results from your database queries.
Once you’ve tested the code and it’s not going to do anything unexpected, uncomment the line that sends the email and you’re all set. If you leave Participants Database debugging on, you will see a record of the outgoing emails in the debugging log.
I also recommend you install an email logging plugin to keep a record of any outgoing emails that have been sent. I like Email Log for that.
Here’s the Code
I wrote this as a plugin, so you can easily install it and run it on your site. Check this post for instructions on how to install this code example as a plugin.
6 thoughts on “Automatically Sending an Email using the WordPress Cron”
Hi sorry to bother you . I have a basic knowledge of PHP and am attempting to build an cron email function to operate on our sites contact form 7 database (we need to run a check to make sure the client has completed all daily / weekly / monthly checks and email them if they have missed a check ) . I see you use $wpdb on your plugin would it just be a question of altering your $sql details (as in the database to check etc) Thankyou so much in advance
This is possible, you won’t need to alter the main plugin code at all to do this, and you shouldn’t do that anyway. In the example plugin provided in the article, you would change the way it checks the Participants Database records and have it check your Contact Form 7 data instead.
You will need to have a pretty solid understanding of how to access that data and determine which people need the reminder. Also, the example plugin keeps track of which people have been notified before, be sure you do that or you will send multiple reminders.
I can’t help you with the technical details, I’m not familiar with the data structures that Contact Form 7 uses.
I have zero coding knowledge but the detailed description of this project pretty much sums up what Im looking for. I would like tot use this to send paid members a reminder to log in if they have not done so for x number of days… that part seems to be covered. Its just then the users membership expires, I would like the emails to stop. The Membership plugin supports changing user rolls so I was thinking of creating new rolls Active Member and Lapsed Member. Would it be possible to add a filter to get_late_accounts() of. specific user roll?
It is possible, but you’re going to have to get some help with that, you will need some developer skills to get that done. It would take some time with you to work out how to do it, and I don’t provide that kind of support, I’m sorry.
I’ve searched and searched but can’t seem to find the answer I am looking for. I want to display the date AND time a record was added publicly.
I added a new Field Group called “Timestamp” and added a field called “timestamp”. How would I set up the field info to display the captured date and time publicly?
There is a field named “date_recorded” that will have this information. It is not normally displayed, but you can force it to display by using the “fields” attribute of the shortcode. That field is the database timestamp string, so it’s not formattable within the plugin configuration.
There is a setting in the plugin settings under the “admin settings” tab that enables showing the time in addition to the date.
However, if you’ve got some coding skills, you can create a custom form element that will mirror the date_recorded field, and in your code you can parse and format it as you like. You may also want to shift the time zone because the timestamp will use the server timezone.