Mailbox cleaner on an IMAP basis?

F

F. GEIGER

Hi all!

As I saw Alex Martelli's post about a mbox cleaner based on POP3, I thought,
it could be possible to do that based on IMAP too. That way I could ask the
server for mails having attached EXE files and delete all those mails on the
server. This would save me a lot of traffic over my phone line connection.

But I'm missing one important thing: How do I get the server to tell me
about attachments.

What I've found out so far is how to get at the fields:

r, d = i.fetch(1, "(BODY.PEEK[HEADER.FIELDS])")

Alas, there's no such thing like 'filename' or 'attachments'.

And

r, d = i.fetch(1, "(BODY.PEEK[HEADER.FIELDS (Content-type)])")

doesn't show a file name either.

Any hints?

Best regards
Franz GEIGER
 
J

John Roth

F. GEIGER said:
Hi all!

As I saw Alex Martelli's post about a mbox cleaner based on POP3, I thought,
it could be possible to do that based on IMAP too. That way I could ask the
server for mails having attached EXE files and delete all those mails on the
server. This would save me a lot of traffic over my phone line connection.

But I'm missing one important thing: How do I get the server to tell me
about attachments.

What I've found out so far is how to get at the fields:

r, d = i.fetch(1, "(BODY.PEEK[HEADER.FIELDS])")

Alas, there's no such thing like 'filename' or 'attachments'.

And

r, d = i.fetch(1, "(BODY.PEEK[HEADER.FIELDS (Content-type)])")

doesn't show a file name either.

Any hints?

Right now, I'd simply like something that would clean out an
IMAP mailbox on a regular basis. Most of the worm generated
garbage is going into one of two boxes on my server, and I get maybe
one legitimate e-mail in those two boxes every couple of weeks.
I can stand to lose that level of e-mail, I can't stand to exceed my disk
quota and lose lots of legitimate mail every few hours.

Could you post the code you've got so far?

Thanks.

John Roth
 
F

F. GEIGER

Well, John,

I've stopped here, because I could not figure out how to get at the ids of
mails with attachments. And if I had that missing link, I'd run into the
next hindrance: How can I delete a single message? IMAP4::delete() deletes a
whole mailbox, not just a single mail.

So my code really is only a few lines so far:

i = IMAP4(myDomain)
i.login(myUser, myPassword)
i.select() # Select INBOX
r, d = i.fetch(1, "(BODY.PEEK[HEADER.FIELDS])") # Check 1st mail

Seems I have to get a book about IMAP and how to use it...

Kind regards
Franz




John Roth said:
F. GEIGER said:
Hi all!

As I saw Alex Martelli's post about a mbox cleaner based on POP3, I thought,
it could be possible to do that based on IMAP too. That way I could ask the
server for mails having attached EXE files and delete all those mails on the
server. This would save me a lot of traffic over my phone line connection.

But I'm missing one important thing: How do I get the server to tell me
about attachments.

What I've found out so far is how to get at the fields:

r, d = i.fetch(1, "(BODY.PEEK[HEADER.FIELDS])")

Alas, there's no such thing like 'filename' or 'attachments'.

And

r, d = i.fetch(1, "(BODY.PEEK[HEADER.FIELDS (Content-type)])")

doesn't show a file name either.

Any hints?

Right now, I'd simply like something that would clean out an
IMAP mailbox on a regular basis. Most of the worm generated
garbage is going into one of two boxes on my server, and I get maybe
one legitimate e-mail in those two boxes every couple of weeks.
I can stand to lose that level of e-mail, I can't stand to exceed my disk
quota and lose lots of legitimate mail every few hours.

Could you post the code you've got so far?

Thanks.

John Roth
Best regards
Franz GEIGER
 
D

Donn Cave

Quoth "F. GEIGER" <[email protected]>:

| I've stopped here, because I could not figure out how to get at the ids of
| mails with attachments. And if I had that missing link, I'd run into the
| next hindrance: How can I delete a single message? IMAP4::delete() deletes a
| whole mailbox, not just a single mail.
|
| So my code really is only a few lines so far:
|
| i = IMAP4(myDomain)
| i.login(myUser, myPassword)
| i.select() # Select INBOX
| r, d = i.fetch(1, "(BODY.PEEK[HEADER.FIELDS])") # Check 1st mail
|
| Seems I have to get a book about IMAP and how to use it...

The IMAP4rev1 RFC of course covers these things, with examples.
2060, I think it is. A message takes two steps to delete: first,
set a \Deleted flag on it, and then invoke expunge on the folder,
which will remove all delete-flagged messages in the folder.

Donn Cave, (e-mail address removed)
 
D

Dominic

server for mails having attached EXE files and delete all those mails on the
server. This would save me a lot of traffic over my phone line connection.

I use a Python script which is run via cron every hour on
a machine with internet connectivity.

It downloads all mails, parses them and does whitelist
filtering but could be easily extentend.

All filtered mails are removed from the mailbox and
stored locally. This mbox file can then be
retrieved by scp/ftp.

Cleaning only every hour has proved to be enough.

Since my script has been running without any
trouble for almost half a year I thought it
may be a basis for ideas or customizing, so
I'll append it to this posting.

Ciao,
Dominic

P.S. You'll need the tpg-parser generator for Python.
 
F

F. GEIGER

Ok, I came up with this so far, many thanks to all who contributed!

Best regards
Franz GEIGER


import os.path, re
from imaplib import *


class Finder:
def __init__(self, text):
self._value = None
results = self._rex.findall(text)
if results:
self._value = results[0]
return

def value(self):
return self._value


class UIDfinder(Finder):

_rex = re.compile(r'UID (\d+)')


class FileNameFinder(Finder):

_rex = re.compile(r'\("application" ".+?" \("name" "(.+?)"\)')

def ft(self):
if not self._value:
return None

root, ft = os.path.splitext(self._value)
return ft


class SenderFinder(Finder):

_rex = re.compile(r'From\: (.+)\r', re.M | re.I)



class SubjectFinder(Finder):

_rex = re.compile(r'Subject\: (.+)\r', re.M | re.I)


class DateFinder(Finder):

_rex = re.compile(r'Date\: (.+)\r', re.M | re.I)


class MessageSummary:
def __init__(self, uid, fileName, text):
if not fileName:
fileName = ''

self._uid = uid
self._fileName = fileName

self._sender = ''
self._subject = ''
self._date = ''

f = SenderFinder(text)
if f.value():
self._sender = f.value()

f = SubjectFinder(text)
if f.value():
self._subject = f.value()

f = DateFinder(text)
if f.value():
self._date = f.value()

return

def __str__(self):
return self.formatted()

def formatted(self):
return "From : %s\nSubject : %s\nAttachment: %s\nFile-Name :
%s" % (self._sender, self._subject, self._date, self._fileName)

def uid(self):
return self._uid


class Deleter:
def __init__(self, server, messageSummaries):
self._server = server
self._messageSummaries = messageSummaries
self._uids = [ms.uid() for ms in self._messageSummaries]
return

def run(self):
uids = ','.join(self._uids)
r = self._server.uid("STORE", uids, "+FLAGS.SILENT", "(\Deleted)")[0]
if r in ("OK", "Ok", "ok"):
return ''
else:
return "Error - Could Not Delete Messages"


class Expunger:
def __init__(self, server):
self._server = server
return

def run(self):
self._server.expunge()
return


print "Logging in."
server = IMAP4("<myDomain>")
server.login("<myUserName>", "<myPassword>")
server.select()


print "Begin to cleanup mailbox."
messagesToDelete = []
i = 0
while (1):
i += 1

r, d = server.fetch(i, "(UID BODY)")
if r == 'NO' or d[0] is None:
break
uid = UIDfinder(d[0]).value()
fnf = FileNameFinder(d[0])
fn = fnf.value()
if not fn:
print '.',
continue

ft = fnf.ft()

r, d = server.fetch(i, "(BODY.PEEK[HEADER.FIELDS (Date From Subject)])")

ms = MessageSummary(uid, fn, d[0][1])

if ft.lower() == ".exe":
print '*',
messagesToDelete.append(ms)
else:
print '.',


if messagesToDelete:
print "\n" * 4
print "%d messages are tagged to be deleted: " % len(messagesToDelete)
for ms in messagesToDelete:
print ms.formatted()
print
print
if raw_input("Shall I delete them now (y/n)? ") == 'y':
print 'Working...'
d = Deleter(server, messagesToDelete)
d.run()
e = Expunger(server)
e.run()
print "Done. "
else:
print
print "No messages to delete. "


raw_input("Press any key to exit...")




Donn Cave said:
Quoth "F. GEIGER" <[email protected]>:

| I've stopped here, because I could not figure out how to get at the ids of
| mails with attachments. And if I had that missing link, I'd run into the
| next hindrance: How can I delete a single message? IMAP4::delete() deletes a
| whole mailbox, not just a single mail.
|
| So my code really is only a few lines so far:
|
| i = IMAP4(myDomain)
| i.login(myUser, myPassword)
| i.select() # Select INBOX
| r, d = i.fetch(1, "(BODY.PEEK[HEADER.FIELDS])") # Check 1st mail
|
| Seems I have to get a book about IMAP and how to use it...

The IMAP4rev1 RFC of course covers these things, with examples.
2060, I think it is. A message takes two steps to delete: first,
set a \Deleted flag on it, and then invoke expunge on the folder,
which will remove all delete-flagged messages in the folder.

Donn Cave, (e-mail address removed)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top