The truth is rarely pure and never simple

How to remain offline and available at the same time

I really like emails. Unfortunately, most of them disturb me when working on a particular issue or talking to people. However, as I wish to be recieve an answer rather quickly, I am keen to answer emails quickly, as well. So how to combine the urge to be available all the time by checking the inbox every time a short glance on the mobile seems acceptable and both concentration and politeness? My suggestion is to check the inbox only on specific times of day. That way, you ensure to read all incoming mail without loosing the influence on your daily schedule.

But how to derive these times? It depends on the personal communication structure. When to most of the emails reach your inbox? How many emails are you recieving in a given time slot? For personal use, I came up with a little (dirty) script that is able to connect to your IMAP account, scan the content of a given set of folders and determine the optimal retrieval times. Here’s the sample output for most of the ham my inbox has seen during 2012.

$ ./imaptime.py
analyzed 10626 emails in total, omitting 1084 outside availability phase
times for  2 fetches a day with costs of  200 delay minutes per mail:
             14:30 23:00
times for  3 fetches a day with costs of  136 delay minutes per mail:
             12:30 17:30 23:00
times for  4 fetches a day with costs of  105 delay minutes per mail:
             12:00 16:30 20:30 23:00
times for  5 fetches a day with costs of   83 delay minutes per mail:
             11:00 14:00 17:30 20:30 23:00
times for  6 fetches a day with costs of   70 delay minutes per mail:
             10:30 13:00 15:30 18:00 20:30 23:00
times for  7 fetches a day with costs of   62 delay minutes per mail:
             10:30 12:30 14:30 16:30 18:30 20:30 23:00

The script is based on the assumption that you need about 30 minutes to actually read and answer all the emails your inbox has collected since your last retrieval. Additionally, the script assumes the user to check the emails just before going to bed.

As usual, you can adjust the settings to match your preferences. The code scales linearly with the number of emails you want to analyze. I do not suggest using a smaller granularity than 30 minutes, as the runtime is O(n!) for n being the number of timeslots per day. (Scanning my inbox and calculating the results took about 10 seconds.) Here is the code:

#!/usr/bin/python
import imaplib
import email.utils
import itertools

## configuration
hostname = 'example.com'
username = 'foobar@example.com'
password = 'example'
folders  = ['example.com', 'INBOX', 'archive', 'Sent']
#availability phase
daystart = (7, 30) # only 0, 30 for minutes
dayend   = (23, 0) # the same

## code
M = imaplib.IMAP4(hostname)
M.login(username, password)
counter = {}

def readbox(boxname, counter, M):
    M.select(boxname, True)
    typ, data = M.search(None, 'ALL')
    if len(data[0]) == 0:
        return
    typ, data = M.search(None, '(UNDELETED)')
    status, result = M.fetch(','.join(data[0].split(' ')), '(BODY[HEADER.FIELDS (DATE)])')
    for mail in result:
        if len(mail) > 1:
            ddata = email.utils.parsedate(mail[1][6:])
            if ddata != None:
                key = '{0:02}:{1:02}'.format(ddata[3], ddata[4])
                key = (int(ddata[3]), int(ddata[4]))
                if key in counter:
                    counter[key] += 1
                else:
                    counter[key] = 1

for i in folders:
    readbox(i, counter, M)
M.close()
M.logout()

rightc = 0
beforec = 0
afterc = 0
dsts = daystart[0]*60+daystart[1]
dets = dayend[0]*60+dayend[1]
costs = [0] * ((dets-dsts)/30)
waiting = [0] * ((dets-dsts)/30)
for k in sorted(counter.iterkeys()):
    cts = k[0]*60+k[1]
    if cts < dsts:
        beforec += counter[k]
    elif cts > dets:
        afterc += counter[k]
    else:
        rightc += counter[k]
        interval = (cts-dsts)/30
        if cts == dets:
            interval -= 1
        waiting[interval] += counter[k]
        costs[interval] += cts-interval*30-dsts

def calccost(costs, waiting, fetchtimes):
    last = 0
    cost = 0
    for i in fetchtimes:
        for k in range(last, i+1):
            cost += costs[k]+waiting[k]*30*(i-k)
        last = i
    return cost

def findmin(costs, waiting, number):
    mincost = 10e10
    mintimes = ()
    for i in itertools.combinations(range(0, len(costs)-2), number-1):
        v = calccost(costs, waiting, i+(len(costs)-1,))
        if v < mincost:
            mincost = v
            mintimes = i
    return (mincost, mintimes+(len(costs),))

sumc = rightc+beforec+afterc
print 'analyzed {0} emails in total, omitting {1} outside availability phase'.format(sumc, (beforec+afterc))
for i in range(2, 8):
    mincost, mintimes = findmin(costs, waiting, i)
    print 'times for {0:2} fetches a day with costs of {1:4} delay minutes per mail:'.format(i, mincost/sumc)
    print ' '*12,
    for j in mintimes:
        h = (dsts+j*30)/60
        m = (dsts+j*30)-h*60
        print '{0:02}:{1:02}'.format(h, m),
    print