3 # This script is released to the public domain.
5 # $ imapquota.py -s imap.mail.drexel.edu xyz12@drexel.edu
7 # Used 92693 of 102400 KB
15 def parse_server(server, ssl=False):
16 server_bits = server.split(':')
17 assert len(server_bits) in [1,2], 'invalid server: %s' % server_bits
18 server = server_bits[0]
19 if len(server_bits) == 2:
27 def traverse_mailboxes(imap_connection, root='""', recursive=False):
28 status,value = imap_connection.list(root, '%')
29 regexp = re.compile(r'\((.*)\) "(.)" (.*)')
30 #status,value = ('OK', [
31 # '(\NoInferiors) "/" INBOX',
32 # '(\HasNoChildren) "/" APS',
34 for mailbox_line in value:
35 if mailbox_line is None:
37 match = regexp.match(mailbox_line)
38 attributes,delimiter,mailbox = match.groups()
39 # TODO: unquote mailbox (if necessary?)
40 yield (attributes, delimiter, mailbox)
42 for attribute in ['\Noinferiors', '\HasNoChildren']:# RFC 2060 and 3348
43 if attribute.lower() in attributes.lower():
46 if not recursive or not children:
48 for m in traverse_mailboxes(imap_connection, root=mailbox):
51 def get_quota(imap_connection, mailbox='inbox'):
52 status,value = imap_connection.getquotaroot(mailbox)
53 #status,value = ('OK',
54 # [['inbox user/xyz12'], ['user/xyz12 (STORAGE 80000 102400)']])
56 regexp = re.compile(r'(.*) \(STORAGE ([0-9]*) ([0-9]*)\)')
57 m = regexp.match(quota)
58 root,used,avail = m.groups()
59 return (root, int(used), int(avail))
61 def get_mailbox_size(imap_connection, mailbox='inbox'):
62 status,value = imap_connection.select(mailbox, readonly=True)
64 raise Exception(value)
65 status,value = imap_connection.search(None, 'ALL')
67 regexp = re.compile(r'.*RFC822\.SIZE ([0-9]*).*')
68 for num in value[0].split():
69 status,value = imap_connection.fetch(num, '(RFC822.SIZE)')
70 #status,value = ('OK', ['231 (RFC822.SIZE 4882)'])
71 match = regexp.match(value[0])
72 msg_size = int(match.group(1))
77 if __name__ == '__main__':
79 p = optparse.OptionParser('%prog SERVER[:port] account',
80 epilog='imapquota -s imap.mail.drexel.edu xyz12@drexel.edu')
81 p.add_option('-s', '--ssl', dest='ssl', default=False, action='store_true',
82 help='Connect over an SSL encrypted socket and change default port to 993.')
83 p.add_option('-m', '--mailbox', dest='mailbox',
84 help='Root mailbox (e.g. INBOX).')
85 p.add_option('-r', '--recursive', dest='recursive', default=False,
87 help='List size of all mailboxes below the root given with `-m`.')
88 options,args = p.parse_args()
91 server,port = parse_server(server, ssl=options.ssl)
92 password = getpass.getpass()
96 if options.ssl == True:
97 i = imaplib.IMAP4_SSL(server, port)
99 i = imaplib.IMAP4(server, port)
100 i.login(account, password)
103 if options.recursive:
105 m for a,d,m in traverse_mailboxes(i, options.mailbox)]
106 mailboxes.insert(0, options.mailbox)
108 mailboxes = [options.mailbox]
109 elif options.recursive:
110 mailboxes = [m for a,d,m in traverse_mailboxes(i)]
112 mailboxes = ['inbox']
113 for mailbox in mailboxes:
114 root,used,avail = get_quota(i, mailbox)
115 if root not in quota_roots:
116 quota_roots[root] = (used, avail)
117 if options.recursive:
118 size = get_mailbox_size(i, mailbox)
119 print '%s used %d B' % (mailbox, size)
123 for root,specs in sorted(quota_roots.iteritems()):
124 used,available = specs
125 print 'quota rooted at %s used %d of %d KB (%.1f percent)' % (
126 root, used, avail, (float(used)/avail*100.0))