From aa0b79b36fac82ea6ac7270a92d835b0a3f95a14 Mon Sep 17 00:00:00 2001 From: Adam Coddington Date: Sat, 30 Jun 2012 22:30:13 -0700 Subject: [PATCH] Adding file-based transports including Maildir, Mbox, Babyl, MH, and MMDF. --- django_mailbox/models.py | 32 +++++++++---- django_mailbox/transports.py | 65 --------------------------- django_mailbox/transports/__init__.py | 7 +++ django_mailbox/transports/babyl.py | 5 +++ django_mailbox/transports/generic.py | 18 ++++++++ django_mailbox/transports/imap.py | 33 ++++++++++++++ django_mailbox/transports/maildir.py | 8 ++++ django_mailbox/transports/mbox.py | 5 +++ django_mailbox/transports/mh.py | 5 +++ django_mailbox/transports/mmdf.py | 5 +++ django_mailbox/transports/pop3.py | 33 ++++++++++++++ readme.rst | 33 +++++++++++++- setup.py | 2 +- 13 files changed, 174 insertions(+), 77 deletions(-) create mode 100644 django_mailbox/transports/__init__.py create mode 100644 django_mailbox/transports/babyl.py create mode 100644 django_mailbox/transports/generic.py create mode 100644 django_mailbox/transports/imap.py create mode 100644 django_mailbox/transports/maildir.py create mode 100644 django_mailbox/transports/mbox.py create mode 100644 django_mailbox/transports/mh.py create mode 100644 django_mailbox/transports/mmdf.py create mode 100644 django_mailbox/transports/pop3.py diff --git a/django_mailbox/models.py b/django_mailbox/models.py index 69666d4..9c26d92 100644 --- a/django_mailbox/models.py +++ b/django_mailbox/models.py @@ -4,7 +4,9 @@ import urllib import urlparse from django.db import models -from django_mailbox.transports import PopMailEnumerator, ImapMailEnumerator +from django_mailbox.transports import Pop3Transport, ImapTransport,\ + MaildirTransport, MboxTransport, BabylTransport, MHTransport, \ + MMDFTransport from django_mailbox.signals import message_received class Mailbox(models.Model): @@ -12,10 +14,10 @@ class Mailbox(models.Model): uri = models.CharField( max_length=255, help_text=""" - Start your URI with imap://, imap+ssl://, pop3://, or pop3+ssl://. + Example: imap+ssl://myusername:mypassword@someserver

- Example: imap://myusername:mypassword@someserver + Internet transports include 'imap' and 'pop3'; common local file transports include 'maildir', 'mbox', and less commonly 'babyl', 'mh', and 'mmdf'.

Be sure to urlencode your username and password should they @@ -60,18 +62,29 @@ class Mailbox(models.Model): def get_connection(self): if self.type == 'imap': - conn = ImapMailEnumerator( + conn = ImapTransport( self.location, port=self.port if self.port else None, ssl=self.use_ssl ) + conn.connect(self.username, self.password) elif self.type == 'pop3': - conn = PopMailEnumerator( + conn = Pop3Transport( self.location, port=self.port if self.port else None, ssl=self.use_ssl ) - conn.connect(self.username, self.password) + conn.connect(self.username, self.password) + elif self.type == 'maildir': + conn = MaildirTransport(self.location) + elif self.type == 'mbox': + conn = MboxTransport(self.location) + elif self.type == 'babyl': + conn = BabylTransport(self.location) + elif self.type == 'mh': + conn = MHTransport(self.location) + elif self.type == 'mmdf': + conn = MMDFTransport(self.location) return conn def get_new_mail(self): @@ -79,10 +92,11 @@ class Mailbox(models.Model): new_mail = [] for message in connection.get_message(): msg = Message() + print msg msg.mailbox = self - msg.subject = message['subject'] - msg.message_id = message['message-id'] - msg.from_address = rfc822.parseaddr(message['from'])[1] + msg.subject = message['subject'][0:255] + msg.message_id = message['message-id'][0:255] + msg.from_address = rfc822.parseaddr(message['from'])[1][0:255] msg.body = message.as_string() msg.save() new_mail.append(msg) diff --git a/django_mailbox/transports.py b/django_mailbox/transports.py index abed1ac..8b13789 100644 --- a/django_mailbox/transports.py +++ b/django_mailbox/transports.py @@ -1,66 +1 @@ -import email -from imaplib import IMAP4, IMAP4_SSL -from poplib import POP3, POP3_SSL - -class PopMailEnumerator(object): - def __init__(self, hostname, port=None, ssl=False): - self.hostname = hostname - self.port = port - if ssl: - self.transport = POP3_SSL - if not self.port: - self.port = 995 - else: - self.transport = POP3 - if not self.port: - self.port = 110 - - def connect(self, username, password): - self.server = self.transport(self.hostname, self.port) - self.server.user(username) - self.server.pass_(password) - - def get_message(self): - message_count = len(self.server.list()[1]) - for i in range(message_count): - try: - msg_contents = "\r\n".join(self.server.retr(i + 1)[1]) - message = email.message_from_string(msg_contents) - yield message - except email.Errors.MessageParseError: - continue - self.server.dele(i + 1) - self.server.quit() - return - -class ImapMailEnumerator(object): - def __init__(self, hostname, port=None, ssl=False): - self.hostname = hostname - self.port = port - if ssl: - self.transport = IMAP4_SSL - if not self.port: - self.port = 993 - else: - self.transport = IMAP4 - if not self.port: - self.port = 143 - - def connect(self, username, password): - self.server = self.transport(self.hostname, self.port) - typ, msg = self.server.login(username, password) - self.server.select() - - def get_message(self): - typ, inbox = self.server.search(None, 'ALL') - for key in inbox[0].split(): - try: - typ, msg_contents = self.server.fetch(key, '(RFC822)') - message = email.message_from_string(msg_contents[0][1]) - yield message - except email.Errors.MessageParseError: - continue - self.server.store(key, "+FLAGS", "\\Deleted"); - self.server.expunge() - return diff --git a/django_mailbox/transports/__init__.py b/django_mailbox/transports/__init__.py new file mode 100644 index 0000000..fc17082 --- /dev/null +++ b/django_mailbox/transports/__init__.py @@ -0,0 +1,7 @@ +from django_mailbox.transports.imap import ImapTransport +from django_mailbox.transports.pop3 import Pop3Transport +from django_mailbox.transports.maildir import MaildirTransport +from django_mailbox.transports.mbox import MboxTransport +from django_mailbox.transports.babyl import BabylTransport +from django_mailbox.transports.mh import MHTransport +from django_mailbox.transports.mmdf import MMDFTransport diff --git a/django_mailbox/transports/babyl.py b/django_mailbox/transports/babyl.py new file mode 100644 index 0000000..674aa2e --- /dev/null +++ b/django_mailbox/transports/babyl.py @@ -0,0 +1,5 @@ +from mailbox import Babyl +from django_mailbox.transports.generic import GenericFileMailbox + +class BabylTransport(GenericFileMailbox): + _variant = Babyl diff --git a/django_mailbox/transports/generic.py b/django_mailbox/transports/generic.py new file mode 100644 index 0000000..059d078 --- /dev/null +++ b/django_mailbox/transports/generic.py @@ -0,0 +1,18 @@ +class GenericFileMailbox(object): + _variant = None + _path = None + + def __init__(self, path): + super(GenericFileMailbox, self).__init__() + self._path = path + + def get_instance(self): + return self._variant(self._path) + + def get_message(self): + repository = self.get_instance() + repository.lock() + for key, message in repository.items(): + repository.remove(key) + yield message + repository.unlock() diff --git a/django_mailbox/transports/imap.py b/django_mailbox/transports/imap.py new file mode 100644 index 0000000..1c57b1c --- /dev/null +++ b/django_mailbox/transports/imap.py @@ -0,0 +1,33 @@ +import email +from imaplib import IMAP4, IMAP4_SSL + +class ImapTransport(object): + def __init__(self, hostname, port=None, ssl=False): + self.hostname = hostname + self.port = port + if ssl: + self.transport = IMAP4_SSL + if not self.port: + self.port = 993 + else: + self.transport = IMAP4 + if not self.port: + self.port = 143 + + def connect(self, username, password): + self.server = self.transport(self.hostname, self.port) + typ, msg = self.server.login(username, password) + self.server.select() + + def get_message(self): + typ, inbox = self.server.search(None, 'ALL') + for key in inbox[0].split(): + try: + typ, msg_contents = self.server.fetch(key, '(RFC822)') + message = email.message_from_string(msg_contents[0][1]) + yield message + except email.Errors.MessageParseError: + continue + self.server.store(key, "+FLAGS", "\\Deleted"); + self.server.expunge() + return diff --git a/django_mailbox/transports/maildir.py b/django_mailbox/transports/maildir.py new file mode 100644 index 0000000..17f7511 --- /dev/null +++ b/django_mailbox/transports/maildir.py @@ -0,0 +1,8 @@ +from mailbox import Maildir +from django_mailbox.transports.generic import GenericFileMailbox + +class MaildirTransport(GenericFileMailbox): + _variant = Maildir + + def get_instance(self): + return self._variant(self._path, None) diff --git a/django_mailbox/transports/mbox.py b/django_mailbox/transports/mbox.py new file mode 100644 index 0000000..708bb33 --- /dev/null +++ b/django_mailbox/transports/mbox.py @@ -0,0 +1,5 @@ +from mailbox import mbox +from django_mailbox.transports.generic import GenericFileMailbox + +class MboxTransport(GenericFileMailbox): + _variant = mbox diff --git a/django_mailbox/transports/mh.py b/django_mailbox/transports/mh.py new file mode 100644 index 0000000..574ccf3 --- /dev/null +++ b/django_mailbox/transports/mh.py @@ -0,0 +1,5 @@ +from mailbox import MH +from django_mailbox.transports.generic import GenericFileMailbox + +class MHTransport(GenericFileMailbox): + _variant = MH diff --git a/django_mailbox/transports/mmdf.py b/django_mailbox/transports/mmdf.py new file mode 100644 index 0000000..ad46284 --- /dev/null +++ b/django_mailbox/transports/mmdf.py @@ -0,0 +1,5 @@ +from mailbox import MMDF +from django_mailbox.transports.generic import GenericFileMailbox + +class MMDFTransport(GenericFileMailbox): + _variant = MMDF diff --git a/django_mailbox/transports/pop3.py b/django_mailbox/transports/pop3.py new file mode 100644 index 0000000..b6943ae --- /dev/null +++ b/django_mailbox/transports/pop3.py @@ -0,0 +1,33 @@ +import email +from poplib import POP3, POP3_SSL + +class Pop3Transport(object): + def __init__(self, hostname, port=None, ssl=False): + self.hostname = hostname + self.port = port + if ssl: + self.transport = POP3_SSL + if not self.port: + self.port = 995 + else: + self.transport = POP3 + if not self.port: + self.port = 110 + + def connect(self, username, password): + self.server = self.transport(self.hostname, self.port) + self.server.user(username) + self.server.pass_(password) + + def get_message(self): + message_count = len(self.server.list()[1]) + for i in range(message_count): + try: + msg_contents = "\r\n".join(self.server.retr(i + 1)[1]) + message = email.message_from_string(msg_contents) + yield message + except email.Errors.MessageParseError: + continue + self.server.dele(i + 1) + self.server.quit() + return diff --git a/readme.rst b/readme.rst index 575bc19..2665f9e 100644 --- a/readme.rst +++ b/readme.rst @@ -7,8 +7,27 @@ This small Django application will allow you to specify IMAP or POP3 mailboxes t WARNING! This app will delete any messages it can find in the inbox you specify-- please make sure you don't have anything important in there. -URI Examples -============ +Setting up your mailbox +======================= + +Django Mailbox supports both common internet mailboxes like POP3 and IMAP as well as local file-based mailboxes. + +.. table:: Protocol Options + + ============ ============== ========================================= + Mailbox Type 'Protocol' Notes + ============ ============== ========================================= + POP3 ``pop3://`` Can also specify SSL with ``pop3+ssl://`` + IMAP ``imap://`` Can also specify SSL with ``imap+ssl://`` + Maildir ``maildir://`` + Mbox ``mbox://`` + Babyl ``babyl://`` + MH ``mh://`` + MMDF ``mmdf://`` + ============ ============== ========================================= + +POP3 and IMAP Mailboxes +----------------------- Mailbox URIs are in the normal URI format:: @@ -23,6 +42,16 @@ If you have an account named 'contemporanea@gmail.com' with a password of '1234' pop3+ssl://contemporanea%40gmail.com:1234@pop.gmail.com +Local File-based Mailboxes +-------------------------- + +If you happen to want to consume a file-based mailbox like an Maildir, Mbox, Babyl, MH, or MMDF mailbox, you can use this too by entering the appropriate 'protocol' in the URI. If you had a maildir, for example, at @/var/mail/@, you would enter a URI like:: + + maildir:///var/mail + +.. important:: + Note that there are three slashes in the above URI. + Subscribing to the incoming mail signal ======================================= diff --git a/setup.py b/setup.py index 84eb31c..aabc8ac 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup, find_packages setup( name='django_mailbox', - version='0.2', + version='1.0', url='http://bitbucket.org/latestrevision/django-mailbox/', description='Automatically import mail from POP3 or IMAP into Django', author='Adam Coddington',