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