1
0
Fork 0

Initial commit.

This commit is contained in:
Adam Coddington 2012-06-27 20:45:01 -07:00
commit 413b60e35f
13 changed files with 340 additions and 0 deletions

2
.hgignore Normal file
View file

@ -0,0 +1,2 @@
.*\.pyc
.*egg-info.*

View file

29
django_mailbox/admin.py Normal file
View file

@ -0,0 +1,29 @@
from django.conf import settings
from django.contrib import admin
from django_mailbox.models import Message, Mailbox
def get_new_mail(mailbox_admin, request, queryset):
for mailbox in queryset.all():
mailbox.get_new_mail()
get_new_mail.short_description = 'Get new mail'
class MailboxAdmin(admin.ModelAdmin):
list_display = (
'name',
'uri',
)
actions = [get_new_mail]
class MessageAdmin(admin.ModelAdmin):
list_display = (
'subject',
'from_address',
'received',
'mailbox',
)
ordering = ['-received']
if getattr(settings, 'DJANGO_MAILBOX_ADMIN_ENABLED', True):
admin.site.register(Message, MessageAdmin)
admin.site.register(Mailbox, MailboxAdmin)

View file

View file

@ -0,0 +1,18 @@
from django.core.management.base import BaseCommand
from django.dispatch import receiver
from django_mailbox.models import Mailbox
from django_mailbox.signals import message_received
class Command(BaseCommand):
def handle(self, *args, **options):
mailboxes = Mailbox.objects.all()
if args:
mailboxes = mailboxes.filter(name = ' '.join(args))
for mailbox in mailboxes:
self.stdout.write('Gathering messages for %s\n' % mailbox.name)
mailbox.get_new_mail()
@receiver(message_received)
def incoming_message(self, sender, message, **kwargs):
self.stdout.write('Received %s\n' % message.subject)

View file

@ -0,0 +1,59 @@
# -*- coding: utf-8 -*-
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
class Migration(SchemaMigration):
def forwards(self, orm):
# Adding model 'Mailbox'
db.create_table('django_mailbox_mailbox', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('name', self.gf('django.db.models.fields.CharField')(max_length=255)),
('uri', self.gf('django.db.models.fields.CharField')(max_length=255)),
))
db.send_create_signal('django_mailbox', ['Mailbox'])
# Adding model 'Message'
db.create_table('django_mailbox_message', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('mailbox', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['django_mailbox.Mailbox'])),
('subject', self.gf('django.db.models.fields.CharField')(max_length=255)),
('message_id', self.gf('django.db.models.fields.CharField')(max_length=255)),
('from_address', self.gf('django.db.models.fields.CharField')(max_length=255)),
('body', self.gf('django.db.models.fields.TextField')()),
('received', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
))
db.send_create_signal('django_mailbox', ['Message'])
def backwards(self, orm):
# Deleting model 'Mailbox'
db.delete_table('django_mailbox_mailbox')
# Deleting model 'Message'
db.delete_table('django_mailbox_message')
models = {
'django_mailbox.mailbox': {
'Meta': {'object_name': 'Mailbox'},
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'name': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'uri': ('django.db.models.fields.CharField', [], {'max_length': '255'})
},
'django_mailbox.message': {
'Meta': {'object_name': 'Message'},
'body': ('django.db.models.fields.TextField', [], {}),
'from_address': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'mailbox': ('django.db.models.fields.related.ForeignKey', [], {'to': "orm['django_mailbox.Mailbox']"}),
'message_id': ('django.db.models.fields.CharField', [], {'max_length': '255'}),
'received': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
'subject': ('django.db.models.fields.CharField', [], {'max_length': '255'})
}
}
complete_apps = ['django_mailbox']

View file

105
django_mailbox/models.py Normal file
View file

@ -0,0 +1,105 @@
import email
import rfc822
import urllib
import urlparse
from django.db import models
from django_mailbox.transports import PopMailEnumerator, ImapMailEnumerator
from django_mailbox.signals import message_received
class Mailbox(models.Model):
name = models.CharField(max_length=255)
uri = models.CharField(
max_length=255,
help_text="""
Start your URI with imap:// or pop3://.
<br />
<br />
Example: imap://myusername:mypassword@someserver
<br />
<br />
Be sure to urlencode your username and password should they
contain illegal characters (like @, :, etc).
"""
)
@property
def _protocol_info(self):
return urlparse.urlparse(self.uri)
@property
def _domain(self):
return self._protocol_info.hostname
@property
def port(self):
return self._protocol_info.port
@property
def username(self):
return urllib.unquote(self._protocol_info.username)
@property
def password(self):
return urllib.unquote(self._protocol_info.password)
@property
def location(self):
return self._domain if self._domain else '' + self._protocol_info.path
@property
def type(self):
return self._protocol_info.scheme.lower()
def get_connection(self):
if self.type == 'imap':
conn = ImapMailEnumerator(
self.location,
self.port if self.port else 143
)
elif self.type == 'pop3':
conn = PopMailEnumerator(
self.location,
self.port if self.port else 110
)
conn.connect(self.username, self.password)
return conn
def get_new_mail(self):
connection = self.get_connection()
new_mail = []
for message in connection.get_message():
msg = Message()
msg.mailbox = self
msg.subject = message['subject']
msg.message_id = message['message-id']
msg.from_address = rfc822.parseaddr(message['from'])[1]
msg.body = message.as_string()
msg.save()
new_mail.append(msg)
message_received.send(sender=self, message=msg)
return new_mail
def __unicode__(self):
return self.name
class Meta:
verbose_name_plural = "Mailboxes"
class Message(models.Model):
mailbox = models.ForeignKey(Mailbox, related_name='messages')
subject = models.CharField(max_length=255)
message_id = models.CharField(max_length=255)
from_address = models.CharField(max_length=255)
body = models.TextField()
received = models.DateTimeField(
auto_now_add=True
)
def get_email_object(self):
return email.message_from_string(self.body)
def __unicode__(self):
return self.subject

View file

@ -0,0 +1,3 @@
from django.dispatch.dispatcher import Signal
message_received = Signal(providing_args=['message'])

View file

@ -0,0 +1,50 @@
import email
from imaplib import IMAP4
from poplib import POP3
class PopMailEnumerator(object):
def __init__(self, hostname, port):
self.hostname = hostname
self.port = port
def connect(self, username, password):
self.server = POP3(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):
self.hostname = hostname
self.port = port
def connect(self, username, password):
self.server = IMAP4(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

56
readme.rst Normal file
View file

@ -0,0 +1,56 @@
Introduction
~~~~~~~~~~~~
How many times have you had to consume some sort of POP3 or IMAP mailbox for incoming content? One too many times for me.
This small Django application will allow you to specify IMAP or POP3 mailboxes that you would like consumed for incoming content; the e-mail will be stored, and you can process it at will (or, if you're in a hurry, by subscribing to a signal).
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
============
Mailbox URIs are in the normal URI format::
protocol://username:password@domain
IMAP Example: ``imap://username:password@server``
POP3 Example: ``pop3://username:password@server``
Subscribing to the incoming mail signal
=======================================
To subscribe to the incoming mail signal, following this lead::
from django_mailbox.signals import message_received
from django.dispatch import receiver
@receiver(message_received)
def dance_jig(sender, message, **args):
print "I just recieved a message titled %s from a mailbox named %s" % (message.subject, message.mailbox.name, )
Getting incoming mail
=======================
In your code
------------
Mailbox instances have a method named ``get_new_mail``; this method will gather new messages from the server.
Using the Django Admin
----------------------
Check the box next to each of the mailboxes you'd like to fetch e-mail from, and select the 'Get new mail' option.
Using a cron job
----------------
You can easily consume incoming mail by running the management command named ``getmail`` (optionally with an argument of the name of the mailbox you'd like to get the mail for).::
python manage.py getmail
Settings
========
You can disable mailbox information from being listed in the Django admin by adding a setting named ``DJANGO_MAILBOX_ADMIN_ENABLED`` indicating your preference toward whether or not the models appear in the admin (defaulting to ``True``).

18
setup.py Normal file
View file

@ -0,0 +1,18 @@
from setuptools import setup, find_packages
setup(
name='django_mailbox',
version='0.1',
url='http://bitbucket.org/latestrevision/django-mailbox/',
description='Automatically import mail from POP3 or IMAP into Django',
author='Adam Coddington',
author_email='me@adamcoddington.net',
classifiers=[
'Intended Audience :: Developers',
'License :: OSI Approved :: MIT License',
'Operating System :: OS Independent',
'Programming Language :: Python',
'Topic :: Utilities',
],
packages=find_packages(),
)