mirror of
https://github.com/coddingtonbear/django-mailbox.git
synced 2026-07-09 22:38:19 +02:00
Initial commit.
This commit is contained in:
commit
413b60e35f
13 changed files with 340 additions and 0 deletions
2
.hgignore
Normal file
2
.hgignore
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
.*\.pyc
|
||||
.*egg-info.*
|
||||
0
django_mailbox/__init__.py
Normal file
0
django_mailbox/__init__.py
Normal file
29
django_mailbox/admin.py
Normal file
29
django_mailbox/admin.py
Normal 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)
|
||||
0
django_mailbox/management/__init__.py
Normal file
0
django_mailbox/management/__init__.py
Normal file
0
django_mailbox/management/commands/__init__.py
Normal file
0
django_mailbox/management/commands/__init__.py
Normal file
18
django_mailbox/management/commands/getmail.py
Normal file
18
django_mailbox/management/commands/getmail.py
Normal 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)
|
||||
59
django_mailbox/migrations/0001_initial.py
Normal file
59
django_mailbox/migrations/0001_initial.py
Normal 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']
|
||||
0
django_mailbox/migrations/__init__.py
Normal file
0
django_mailbox/migrations/__init__.py
Normal file
105
django_mailbox/models.py
Normal file
105
django_mailbox/models.py
Normal 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
|
||||
3
django_mailbox/signals.py
Normal file
3
django_mailbox/signals.py
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
from django.dispatch.dispatcher import Signal
|
||||
|
||||
message_received = Signal(providing_args=['message'])
|
||||
50
django_mailbox/transports.py
Normal file
50
django_mailbox/transports.py
Normal 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
56
readme.rst
Normal 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
18
setup.py
Normal 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(),
|
||||
)
|
||||
Loading…
Add table
Add a link
Reference in a new issue