extrapole
clone your own copy | download snapshot

Snapshots | iceberg

No images in this repository’s iceberg at this time

Inside this repository

models.py
text/x-python

Download raw (5.4 KB)

# -*- coding: utf-8 -*-
"""
 
 django_maildir.models

 read-only models to access Maildirs
 It assumes postfix virtual domains configuration
 
 settings must have POSTFIX_VIRTUAL_MAILBOX_BASE
"""

import os
from mailbox import Maildir, MaildirMessage
from email.header import decode_header
from email.utils import parsedate_tz, mktime_tz, parseaddr
from django.utils import formats
import datetime
import time
import codecs

import logging
logger = logging.getLogger(__name__)

from django_postfix.models import PostfixMailbox
from settings import POSTFIX_VIRTUAL_MAILBOX_BASE

class MessageKey(object):
    def __init__(self, domain, mailbox, key):
        self.domain = domain
        self.mailbox = mailbox
        self.key = key
        
    def file_url(self, fn, proto='http'):
        parts = [
            '%s://'%proto, 
            self.domain, 
            'maildir', 
            'file', 
            '%s@%s'%(self.mailbox, self.domain), 
            self.key, 
            fn
            ]
        url = '/'.join(parts)
        return url

class Message(object):
    """
    present a model for a message, everything in ther :)
    """
    
    def __init__(self):
        self.maildirs = {}
        self.codecs = {}
        
        mailboxes = PostfixMailbox.objects.all()
        for mb in mailboxes:
            try:
                mb_path = os.path.join(POSTFIX_VIRTUAL_MAILBOX_BASE, mb.domain.name, mb.name)
                print 'Try to MD: %s'%mb_path
                if mb.domain.name not in self.maildirs:
                    self.maildirs[mb.domain.name] = {}
                self.maildirs[mb.domain.name][mb.name] = Maildir(mb_path, factory=None, create=False)
            except Exception as e:
                logger.error(e)
                
                
    def mail_decode(self, text, charset):
        if charset is None:
            charset = 'us-ascii'
        if charset not in self.codecs:
            self.codecs[charset] = codecs.getdecoder(charset)
        u, c = self.codecs[charset](text)
        return u
        
    def get_header(self, header, message):
        raw_header = decode_header(message.get(header, 'No %s'%header))
        header_parts = []
        for decoded_string, charset in raw_header:
            header_parts.append(self.mail_decode(decoded_string, charset))
        return  u' '.join(header_parts)
        
    def parse_subject(self,  message , msg_key, response):
        subject = self.get_header('Subject', message)
        subject_list = subject.split('#')
        response['subject'] = subject_list.pop(0)
        response['tags'] = []
        for t in subject_list:
            response['tags'].append(t.strip())
            
    def parse_body(self, message , msg_key, response):
        response['body'] = []
        for part in message.walk():
            T = part.get_content_maintype()
            if T == 'multipart':
                continue
            elif T == 'text':
                charset = part.get_charsets()[0]
                text = part.get_payload(decode=True)
                response['body'].append({
                    'type':part.get_content_type(), 
                    'payload':self.mail_decode(text, charset)
                    })
            else:
                response['body'].append({
                    'type':part.get_content_type(),
                    'payload': msg_key.file_url( part.get_filename() ),
                    'filename': part.get_filename()
                    })
    
    def parse_recipient(self,  message , msg_key, response):
        paddr = parseaddr(self.get_header('To', message))
        addr = paddr[0]
        if not addr:
            addr = paddr[1].split('@')[0]
        response['to'] = addr
        
    def parse_sender(self,  message , msg_key, response):
        paddr = parseaddr(self.get_header('From', message))
        addr = paddr[0]
        if not addr:
            addr = paddr[1].split('@')[0]
        response['from'] = addr
        
    def parse_date(self, message , msg_key, response):
        d = self.get_header('Date', message)
        date_tuple = parsedate_tz(d)
        timestamp = mktime_tz(date_tuple)
        date = datetime.datetime.fromtimestamp(timestamp)
        response['date'] = formats.date_format(date, 'DATE_FORMAT')
        response['time'] = formats.date_format(date, 'TIME_FORMAT')
        response['timestamp'] = timestamp
    
    def message_prepare(self, message , msg_key):
        ret = {}
        parts = ['subject', 'body', 'recipient', 'date', 'sender']
        for part in parts:
            getattr(self, '_'.join(['parse',part]))(message, msg_key, ret)
        return ret 
        
    def get_file(self, mailbox, key, filename):
        mb, domain = list(mailbox.split('@'))
        md = self.maildirs[domain][mb]
        message = md.get(key)
        for part in message.walk():
            if filename == part.get_filename():
                return {'mimetype':part.get_content_type(), 'data':part.get_payload(decode=True)}
                
    def get_all(self):
        ret = []
        for domain in self.maildirs:
            for mailbox in self.maildirs[domain]:
                md = self.maildirs[domain][mailbox]
                for (k,m) in md.iteritems():
                    mp = self.message_prepare(m, MessageKey(domain, mailbox, k))
                    mp['mailbox'] = '%s@%s'%(mailbox, domain)
                    mp['key'] = k
                    ret.append(mp)
                    
        return ret