2012-06-27 20:45:01 -07:00
|
|
|
import email
|
|
|
|
|
import rfc822
|
|
|
|
|
import urllib
|
|
|
|
|
import urlparse
|
|
|
|
|
|
|
|
|
|
from django.db import models
|
2012-06-30 22:30:13 -07:00
|
|
|
from django_mailbox.transports import Pop3Transport, ImapTransport,\
|
|
|
|
|
MaildirTransport, MboxTransport, BabylTransport, MHTransport, \
|
|
|
|
|
MMDFTransport
|
2012-06-27 20:45:01 -07:00
|
|
|
from django_mailbox.signals import message_received
|
|
|
|
|
|
2012-10-09 05:52:04 +00:00
|
|
|
class ActiveMailboxManager(models.Manager):
|
|
|
|
|
def get_query_set(self):
|
|
|
|
|
return super(ActiveMailboxManager, self).get_query_set().filter(
|
|
|
|
|
active=True,
|
|
|
|
|
)
|
|
|
|
|
|
2012-06-27 20:45:01 -07:00
|
|
|
class Mailbox(models.Model):
|
|
|
|
|
name = models.CharField(max_length=255)
|
|
|
|
|
uri = models.CharField(
|
|
|
|
|
max_length=255,
|
|
|
|
|
help_text="""
|
2012-06-30 22:30:13 -07:00
|
|
|
Example: imap+ssl://myusername:mypassword@someserver
|
2012-06-27 20:45:01 -07:00
|
|
|
<br />
|
|
|
|
|
<br />
|
2012-06-30 22:30:13 -07:00
|
|
|
Internet transports include 'imap' and 'pop3'; common local file transports include 'maildir', 'mbox', and less commonly 'babyl', 'mh', and 'mmdf'.
|
2012-06-27 20:45:01 -07:00
|
|
|
<br />
|
|
|
|
|
<br />
|
|
|
|
|
Be sure to urlencode your username and password should they
|
|
|
|
|
contain illegal characters (like @, :, etc).
|
2012-10-07 19:43:38 -07:00
|
|
|
""",
|
|
|
|
|
blank=True,
|
2012-10-08 15:24:42 +00:00
|
|
|
null=True,
|
2012-10-07 19:43:38 -07:00
|
|
|
default=None,
|
2012-06-27 20:45:01 -07:00
|
|
|
)
|
2012-10-09 05:52:04 +00:00
|
|
|
active = models.BooleanField(
|
|
|
|
|
blank=True,
|
|
|
|
|
default=True,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
objects = models.Manager()
|
|
|
|
|
active_mailboxes = ActiveMailboxManager()
|
2012-06-27 20:45:01 -07:00
|
|
|
|
|
|
|
|
@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):
|
2012-06-30 19:08:18 +00:00
|
|
|
scheme = self._protocol_info.scheme.lower()
|
|
|
|
|
if '+' in scheme:
|
|
|
|
|
return scheme.split('+')[0]
|
|
|
|
|
return scheme
|
|
|
|
|
|
|
|
|
|
@property
|
|
|
|
|
def use_ssl(self):
|
|
|
|
|
return '+ssl' in self._protocol_info.scheme.lower()
|
2012-06-27 20:45:01 -07:00
|
|
|
|
|
|
|
|
def get_connection(self):
|
2012-10-08 15:30:32 +00:00
|
|
|
if not self.uri:
|
|
|
|
|
return None
|
|
|
|
|
elif self.type == 'imap':
|
2012-06-30 22:30:13 -07:00
|
|
|
conn = ImapTransport(
|
2012-06-27 20:45:01 -07:00
|
|
|
self.location,
|
2012-06-30 19:08:18 +00:00
|
|
|
port=self.port if self.port else None,
|
|
|
|
|
ssl=self.use_ssl
|
2012-06-27 20:45:01 -07:00
|
|
|
)
|
2012-06-30 22:30:13 -07:00
|
|
|
conn.connect(self.username, self.password)
|
2012-06-27 20:45:01 -07:00
|
|
|
elif self.type == 'pop3':
|
2012-06-30 22:30:13 -07:00
|
|
|
conn = Pop3Transport(
|
2012-06-27 20:45:01 -07:00
|
|
|
self.location,
|
2012-06-30 19:08:18 +00:00
|
|
|
port=self.port if self.port else None,
|
|
|
|
|
ssl=self.use_ssl
|
2012-06-27 20:45:01 -07:00
|
|
|
)
|
2012-06-30 22:30:13 -07:00
|
|
|
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)
|
2012-06-27 20:45:01 -07:00
|
|
|
return conn
|
|
|
|
|
|
2012-10-08 03:07:30 +00:00
|
|
|
def process_incoming_message(self, message):
|
|
|
|
|
msg = Message()
|
|
|
|
|
msg.mailbox = self
|
|
|
|
|
msg.subject = message['subject'][0:255]
|
|
|
|
|
msg.message_id = message['message-id'][0:255]
|
2012-10-27 17:46:48 -07:00
|
|
|
msg.from_header = message['from']
|
|
|
|
|
msg.to_header = message['to']
|
|
|
|
|
msg.outgoing = False
|
2012-10-08 03:07:30 +00:00
|
|
|
msg.body = message.as_string()
|
2012-10-09 05:52:04 +00:00
|
|
|
if message['in-reply-to']:
|
|
|
|
|
try:
|
|
|
|
|
msg.in_reply_to = Message.objects.filter(message_id=message['in-reply-to'])[0]
|
|
|
|
|
except IndexError:
|
|
|
|
|
pass
|
2012-10-08 03:07:30 +00:00
|
|
|
msg.save()
|
2012-10-09 05:52:04 +00:00
|
|
|
if message['references']:
|
|
|
|
|
references = message['references'].split('\n')
|
|
|
|
|
for reference in references:
|
|
|
|
|
try:
|
|
|
|
|
msg.references.add(
|
|
|
|
|
Message.objects.filter(message_id=reference.strip())[0]
|
|
|
|
|
)
|
|
|
|
|
except IndexError:
|
|
|
|
|
pass
|
2012-10-08 03:07:30 +00:00
|
|
|
message_received.send(sender=self, message=msg)
|
|
|
|
|
return msg
|
|
|
|
|
|
2012-06-27 20:45:01 -07:00
|
|
|
def get_new_mail(self):
|
|
|
|
|
new_mail = []
|
2012-10-08 15:30:32 +00:00
|
|
|
connection = self.get_connection()
|
|
|
|
|
if not connection:
|
|
|
|
|
return new_mail
|
2012-06-27 20:45:01 -07:00
|
|
|
for message in connection.get_message():
|
2012-10-08 03:07:30 +00:00
|
|
|
msg = self.process_incoming_message(message)
|
2012-06-27 20:45:01 -07:00
|
|
|
new_mail.append(msg)
|
|
|
|
|
return new_mail
|
|
|
|
|
|
|
|
|
|
def __unicode__(self):
|
|
|
|
|
return self.name
|
|
|
|
|
|
|
|
|
|
class Meta:
|
|
|
|
|
verbose_name_plural = "Mailboxes"
|
|
|
|
|
|
2012-10-09 05:52:04 +00:00
|
|
|
class IncomingMessageManager(models.Manager):
|
|
|
|
|
def get_query_set(self):
|
|
|
|
|
return super(IncomingMessageManager, self).get_query_set().filter(
|
|
|
|
|
outgoing=False,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
class OutgoingMessageManager(models.Manager):
|
|
|
|
|
def get_query_set(self):
|
|
|
|
|
return super(OutgoingMessageManager, self).get_query_set().filter(
|
|
|
|
|
outgoing=True,
|
|
|
|
|
)
|
|
|
|
|
|
2012-06-27 20:45:01 -07:00
|
|
|
class Message(models.Model):
|
|
|
|
|
mailbox = models.ForeignKey(Mailbox, related_name='messages')
|
|
|
|
|
subject = models.CharField(max_length=255)
|
|
|
|
|
message_id = models.CharField(max_length=255)
|
2012-10-09 05:52:04 +00:00
|
|
|
in_reply_to = models.ForeignKey(
|
|
|
|
|
'django_mailbox.Message',
|
|
|
|
|
related_name='replies',
|
|
|
|
|
blank=True,
|
|
|
|
|
null=True,
|
|
|
|
|
)
|
|
|
|
|
references = models.ManyToManyField(
|
|
|
|
|
'django_mailbox.Message',
|
|
|
|
|
related_name='referenced_by',
|
|
|
|
|
blank=True,
|
|
|
|
|
null=True,
|
|
|
|
|
)
|
2012-10-27 17:46:48 -07:00
|
|
|
from_header = models.CharField(
|
|
|
|
|
max_length=255,
|
|
|
|
|
)
|
|
|
|
|
to_header = models.TextField()
|
2012-10-09 05:52:04 +00:00
|
|
|
outgoing = models.BooleanField(
|
|
|
|
|
default=False,
|
|
|
|
|
blank=True,
|
|
|
|
|
)
|
2012-06-27 20:45:01 -07:00
|
|
|
|
|
|
|
|
body = models.TextField()
|
|
|
|
|
|
2012-10-09 05:52:04 +00:00
|
|
|
processed = models.DateTimeField(
|
|
|
|
|
auto_now_add=True
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
objects = models.Manager()
|
|
|
|
|
incoming_messages = IncomingMessageManager()
|
|
|
|
|
outgoing_messages = OutgoingMessageManager()
|
|
|
|
|
|
2012-10-27 17:46:48 -07:00
|
|
|
@property
|
|
|
|
|
def address(self):
|
|
|
|
|
"""Property allowing one to get the relevant address(es).
|
|
|
|
|
|
|
|
|
|
In earlier versions of this library, the model had an `address` field
|
|
|
|
|
storing the e-mail address from which a message was received. During
|
|
|
|
|
later refactorings, it became clear that perhaps storing sent messages
|
|
|
|
|
would also be useful, so the address field was replaced with two
|
|
|
|
|
separate fields.
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
if self.outgoing:
|
|
|
|
|
return self.to_addresses()
|
|
|
|
|
else:
|
|
|
|
|
return self.from_addresses()
|
|
|
|
|
|
2012-10-09 05:52:04 +00:00
|
|
|
@property
|
|
|
|
|
def from_address(self):
|
2012-10-27 17:46:48 -07:00
|
|
|
return rfc822.parseaddr(self.from_header)[1]
|
2012-10-09 05:52:04 +00:00
|
|
|
|
|
|
|
|
@property
|
2012-10-27 17:46:48 -07:00
|
|
|
def to_addresses(self):
|
|
|
|
|
addresses = []
|
|
|
|
|
for address in self.to_header.split(','):
|
|
|
|
|
addresses.append(
|
|
|
|
|
rfc822.parseaddr(
|
|
|
|
|
address
|
|
|
|
|
)[1]
|
|
|
|
|
)
|
|
|
|
|
return addresses
|
2012-06-27 20:45:01 -07:00
|
|
|
|
|
|
|
|
def get_email_object(self):
|
|
|
|
|
return email.message_from_string(self.body)
|
|
|
|
|
|
|
|
|
|
def __unicode__(self):
|
|
|
|
|
return self.subject
|