Skip to content

Instantly share code, notes, and snippets.

@bootandy
Last active December 14, 2015 09:19
Show Gist options
  • Save bootandy/5064264 to your computer and use it in GitHub Desktop.
Save bootandy/5064264 to your computer and use it in GitHub Desktop.
python - logs into email and prints your oyster card costs per month by looking for the 'Oyster card topped up' messages in your TFL_MAILBOX email folder
import imaplib
import email
from pprint import pprint
import re
import collections
from email.Iterators import typed_subpart_iterator
""" Assumes you have TFL email you each time your oyster auto top up occurs """
USERNAME = "" # Gmail user
PASSWORD = "" # Gmail pass
TFL_MAILBOX = "good mailshots/trains/tfl" # Gmail label where your TFL emails go to
def get_charset(message, default="ascii"):
"""Get the message charset"""
if message.get_content_charset():
return message.get_content_charset()
if message.get_charset():
return message.get_charset()
return default
def get_body(message):
"""Get the body of the email message"""
if message.is_multipart():
#get the plain text version only
text_parts = [part
for part in typed_subpart_iterator(message,
'text',
'plain')]
body = []
for part in text_parts:
charset = get_charset(part, get_charset(message))
body.append(unicode(part.get_payload(decode=True),
charset,
"replace"))
return u"\n".join(body).strip()
else: # if it is not multipart, the payload will be a string
# representing the message body
body = unicode(message.get_payload(decode=True),
get_charset(message),
"replace")
return body.strip()
money_pattern = re.compile("was topped up with .?(\d+)")
money_pattern_html = re.compile("was topped up with £(\d+)")
def extract_money(payload):
return int(money_pattern.search(payload).group(1))
conn = imaplib.IMAP4_SSL("imap.gmail.com", 993)
conn.login(USERNAME, PASSWORD)
conn.select()
try:
conn.select(TFL_MAILBOX)
typ, msg_ids = conn.search(None, '(SUBJECT "Your Oyster card has been topped up")')
result = []
for num in msg_ids[0].split():
typ, msg_data = conn.fetch(num, '(RFC822)')
for response_part in msg_data:
if isinstance(response_part, tuple):
msg = email.message_from_string(response_part[1])
body = get_body(msg)
try:
result.append( (msg.get('date'), extract_money(body)) )
except Exception, e:
print e
print body
print 'bad one on day: ' + msg.get('date')
r_map = collections.OrderedDict()
for r in result:
index = r[0].split()[3] + r[0].split()[2]
r_map.setdefault(index, 0)
r_map[index] += r[1]
for r,v in r_map.items():
print r + ':' + str(v)
finally:
try:
conn.close()
except:
pass
conn.logout()
# list_response_pattern = re.compile(r'\((?P<flags>.*?)\) "(?P<delimiter>.*)" (?P<name>.*)')
# def parse_list_response(line):
# flags, delimiter, mailbox_name = list_response_pattern.match(line).groups()
# mailbox_name = mailbox_name.strip('"')
# return (flags, delimiter, mailbox_name)
# def view_mailboxes(conn):
# typ, data = conn.list()
# for line in data:
# flags, delimiter, mailbox_name = parse_list_response(line)
# print conn.status(mailbox_name, '(MESSAGES RECENT UIDNEXT UIDVALIDITY UNSEEN)')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment