Gmail Scheduler
Google operates one of the largest email platforms online. Gmail is a very feature packed email platform, and it’s highly extensible too, given the extremely programmable platform it is running on.
gmail scheduler
Today we are writing a email scheduler for gmail. You specify the time and your mail gets sent at a future date, without the need to manually click the send button.
There are many gmail scheduling scripts out there. And here, we are going to learn and implement one for ourselves. Let’s get down to business.
main idea
The timestamp for the delivery will be included in the subject. Every hour, the script will go searching for emails of a certain label. If the mail is to be sent, out it goes, else, it will sit there in your drafts, waiting for the delivery time.
This system is designed to be built into the Gmail workflow. This way, you can still work on your drafts, handle emails normally as you would without having to mess around with other interfaces.
For this project, we will be working on the Google app script. It is a javascript based programmable interface that supports the interaction with the various Google application.
the details
There are a few interfaces for the email platform. The particular one we will be using in this project is the GmailApp interface accessible via Google App Script.
Sidetrack: The MailApp can only be used to send emails. The GmailApp, on the other hand, is used to access your mails (drafts, labels, etc).
the basic structure
GmailApp has 2 main tiers of abstraction — email threads and messages. Email threads is the main way we will use GmailApp to identify and category mail. For instance, search results will return mail threads, and labels will be tagged particular threads.
These threads contain messages. Each message object will be the individual emails (received, sent or draft). Each message will contain the typical fields — subject, to, cc, etc
For a fuller picture of how the whole structure of GmailApp works, do give the documentation a quick read. Go on, I will still be around when you get back.
the code
forming the date string
This part of the code takes up a few lines. Main reason is that there is no function for us to easily convert the date into the YYYYMMDD.HHmm format. This section of the code includes a padding function to add 0 to the date for the right format.
This particular date format is chosen to allow us to check the timestamp using a simple string comparism. This is also why we have the date and time defined at the front of the subject. (Another reason is because it is easier to view on the Gmail UI at one glance when each mail is to be sent)
main logic
We search for all email threads labeled schedule. Then for each thread, we will check through all of the messages for those draft email. This is where the date string comes in.
If the subject of the message is smaller than the current date string, we will send out the message. But why do we forward the message instead of just sending it?
The programmable interface does not have such support for sending out drafts. Instead, we work around this by creating a new message with the same details and content. After sending the message out, we will bin the original message and remove the label on the thread.
design considerations
There are a few cases that we have taken into consideration in the piece of code above.
existence of multiple drafts
What if there is multiple draft messages in a thread that is marked schedule? There are some cases where you want to send a specific reply to different people.
Hence the counter in the main logic. Every draft message adds one to the counter, and every message sent removes one.
So in the case where one of them is sent, leaving one still in draft, the label will still be kept and the script will still process the thread in the next round.
draft not yet complete
Let’s say you have your draft written halfway, you tagged the thread with the schedule label but you haven’t complete it so you didn’t put a date in the subject, what then?
By nature of string comparison, numbers come first. Since our date string is all numbers, a subject without a date format in the front will always be greater (in terms of string comparison).
A subject without a valid date format in the front won’t trigger the sending action. So you wont send out uncompleted emails.
Note: this is under the assumption that your email subject doesn’t start with a bunch of numbers. This assumption holds pretty well for daily emailing purposes.
bug: subject contains timestamp
I have been using it for a while, and it seems like when the scheduled mail is replied, the timestamp will be included inside the subject of the email thread. But after some debugging I found the problem, and the solution is a simple one-liner — msg.markRead().
Why is this markRead() function so crucial? The subject of a thread is determined by the latest message of the email thread. In a previous revision of the script, I merely move the message to trash. Since the unread deleted draft is recognized as the latest message in the thread, the thread will take the subject with the timestamp.
By marking the discarded message as read, the email message sent out (the forwarded message) is recognized as the latest of the thread. This fixes the problem of the timestamp appear in your email inbox.
Well… it’s not so easy
Looks like reading it is not enough. You have to delete the whole message in order to ensure it does not recognize the draft as part of the thread. Marking it as read works temporarily. But after a while, the subject pops back to the draft subject.
GmailApp doesn’t support deleting of messages (trash is move to bin, delete is permanently delete). Hence, we will be using the much more feature packed Gmail API instead (the one we used previously is GmailApp).
To permanently delete the post, this is the particular function call that we will be using Gmail.Users.Messages.remove('me', msg.getId());. To view more details on the full Gmail API, you can view the documentation.
note: If you have trouble running the code, you probably need to activate the advance services. You can view the instructions on the advance services section.
running it
The last and most crucial step will be to schedule the script to run at a regular interval to keep checking if there is any mail to be sent.
This is done under Edit > Current Project's trigger in the script menu. Create a new time based trigger. Now the function will run at a fixed time interval.
The precision of this system relies on how frequency you set the script to run. If you have no need for the system to be too precise, perhaps running the script hourly will do. That said, you can set the script to run every minute too (highest frequency for time-based trigger).
If you want to have a feature packed email scheduling system, you can take a look at those available out there (Boomerang, email scheduler, etc).
