Delivery Reminder

AppsScript, Gmail, Calendar

Created by Nirvana Tikku / @ntikku

What is it?


Google Apps Script deployed webapp. onInstall seeds ScriptDb with all users foodler orders. Runs automated services that create calendar events for new orders as they come into your gmail.

How does it work?


AppsScript Triggers + Gmail & Calendar Services.

Triggers

(1) Check Gmail to see if any new emails from orders@foodler.comStore in ScriptDb if they exist
every 5 minutes

(2) Check ScriptDb to see if there are any new orders – Create calendar notifications if they exist
every minute

Gmail

Search Gmail for emails from Foodler


// qry like: subject: "Foodler order #" from:orders@foodler.com
var query = 'subject:"'+_.subject_regex+'" from:"'+_.email+'"';

// get all the threads based on the query
var threads = GmailApp.search(query);

// get all the messages for those threads -- huge performance win!
var threadMessages = GmailApp.getMessagesForThreads(threads);
	

Calendar

Create a calendar entry for the order


// get the calendar
var cal = CalendarApp.getDefaultCalendar();

// we'll build freeform text, more forgiving
var freeformText = order.restaurant + ' delivery from ';
freeformText += order.processed + '-' + order.delivery;

// create the event
var evt = cal.createEventFromDescription(freeformText);

// store some additional information
evt.setDescription("OrderID: " + order.orderID);

// we know the location
evt.setLocation(order.destination);
	

Calendar

Create a calendar entry for the delivery

// 
// create an event at the time that the order is ending
var title = order.restaurant + ' Delivery Should Have Arrived!';
var evtTime = evt.getEndTime();
var reminderEvt = cal.createEvent(title, evtTime, evtTime);

// the three kinds of reminders
reminderEvt.addSmsReminder(_.reminder_period); // mins
reminderEvt.addEmailReminder(_.reminder_period);
reminderEvt.addPopupReminder(_.reminder_period);
	

Parsing the email

Parse Gmail message body with XML Services


// pseudo-xpath
order_restaurant_xpath: 
	'html.body.div.table[0].tr[0].td.table.tr[1].td.b'

// parse as xml
xmlBody = Xml.parse(msg.getBody(),true);

// use eval to avoid having to build out the node path expression
var restaurant = eval('xmlDoc.' + _.order_restaurant_xpath).Text;
	

Using ScriptDb

Remember, ScriptDb storage is per script


// filter on a specified `type` and the current user 
var latestOrderQuery = _.db.query({
	type: _.type, 
	calEventCreated: false, 
	userid: _.getUserID()
});

// dealing with numbers in strings? NUMERIC sortStrategy ftw!
latestOrderQuery.sortBy("orderID", _.db.DESCENDING, _.db.NUMERIC);

// save performance win
_.db.saveBatch([], false);
	

FWIW, 40s to clear 400 records; 40s to save 400 records.

Building HTML

HTMLService allows you to include JavaScript that will execute functions defined in Code.gs.


// the AS get method request handler
function doGet() {
	return HtmlService.createHtmlOutputFromFile('Orders');
}

// invoke functions defined in AS code in HTML templates JS, 
// in this case, Orders.html
google.script.run.withSuccessHandler(function(res){})
	.withFailureHandler(function(res){})
	.fetchOrders(++currentPage);
	

Tips

  • Trigger failure notifications
    → set to immediate when debugging
  • HTMLService uses Google Caja
    → you can't use just any js library (✓jquery1.7)
  • HTML requests to AS are blocking
    → should paginate/batch ops

Code?

github.com/nirvanatikku/foodler_delivery_reminder