Wednesday, 9 September 2015

Python: Office 365 alerts on Linux

It is possible to use Microsoft's Office 365 with native Linux clients for mail and calendar:

However, neither have proven reliable. The web interface is good but being browser based has meeting and new mail alert limitations. Fortunately, Office 365 has a REST API...

Some familiarity with Python is assumed.

Office 365 API 🔗

Links:

The API is not final at time of writing:

This documentation covers features that are currently in preview. For information about working with preview features, see Preview developer features on the Office 365 platform.

Reading the Calendar 🔗

This Python code uses the Calendar API to read events up to a specified number of minutes in the future:

def find_events(): now = datetime.datetime.utcnow() start_date_time = now.isoformat() future = now + datetime.timedelta(minutes=delay_mins) end_date_time = future.isoformat() query = 'startDateTime=' + start_date_time + '&endDateTime=' + end_date_time + '&$select=Subject,Start,End,Location' url = 'https://outlook.office.com/api/v1.0/me/calendarview?' print 'GET', url r = requests.get(url, auth=(user, pw)) r.raise_for_status() return r.json() 

The service returns any Calendar events that intersect with the startDateTime and endDateTime range.

The Python Requests library is used in this sample.

Displaying Alerts 🔗

The notify-send program is commonly used to display messages in the notification area in Linux desktop systems. This application can be invoked from Python:

def send_message(message): subprocess.Popen(['notify-send', message]) 

The message will appear and fade without user intervention or focus stealing.

Notification Script 🔗

Here is a command-line proof-of-concept script:

import subprocess import requests import getpass import datetime import threading import time user = raw_input("User: ") pw = getpass.getpass() delay_mins = 5 def find_events(): now = datetime.datetime.utcnow() start_date_time = now.isoformat() future = now + datetime.timedelta(minutes=delay_mins) end_date_time = future.isoformat() query = 'startDateTime=' + start_date_time + '&endDateTime=' + end_date_time + '&$select=Subject,Start,End,Location' url = 'https://outlook.office.com/api/v1.0/me/calendarview?' print 'GET', url r = requests.get(url, auth=(user, pw)) r.raise_for_status() return r.json() def send_message(message): subprocess.Popen(['notify-send', message]) def raise_message_at(delay_seconds, message): t = threading.Timer(delay_seconds, lambda: send_message(message)) t.start() return t def process_event(evt): start_str = evt['Start'] start = datetime.datetime.strptime(start_str, '%Y-%m-%dT%H:%M:%SZ') now = datetime.datetime.utcnow() if start < now: return delay = (start - datetime.datetime.utcnow()) location = evt['Location'] location_name = location['DisplayName'] subject = evt['Subject'] print 'Alerting', subject, ' in ', delay raise_message_at(delay.seconds, location_name + ': ' + subject) while True: try: response = find_events() print response events = response['value'] for event in events: process_event(event) except Exception as e: print e time.sleep(delay_mins * 60) 

There is much room for improvement.

No comments:

Post a Comment

All comments are moderated