django-informativo / informativo /

import smtplib

from datetime import datetime

from django.conf import settings
from django.core.exceptions import ValidationError
from django.db import models
from django.utils.translation import ugettext_lazy as _

from informativo.utils import send_mass_mail

    ('canceled', _('canceled')),
    ('waiting', _('waiting sending')),
    ('sending', _('sending')),
    ('sent', _('sent')),

    ('canceled', _('canceled')),
    ('sending', _('sending')),
    ('sent', _('sent')),
    ('failed', _('failed')),

def get_default_mainlist():
    ids = MailingList.objects.values_list('id', flat=True)
    if len(ids) == 1:
        return ids
    return []

class Contact(models.Model):
    first_name = models.CharField(_('first name'), max_length=64, blank=True)
    last_name = models.CharField(_('last name'), max_length=64, blank=True)
    email = models.EmailField(_('e-mail'), unique=True)
    mailing_lists = models.ManyToManyField(
        verbose_name=_('mailing lists'),

    class Meta:
        verbose_name = _('contact')
        verbose_name_plural = _('contacts')
        ordering = ('-id',)

    def __unicode__(self):
        if self.first_name and self.last_name:
            return u'%s %s <%s>' % (self.first_name, self.last_name,
        return u'%s' %

class MailingList(models.Model):
    name = models.CharField(_('name'), max_length=64)
    description = models.TextField(_('description'), blank=True)

    class Meta:
        verbose_name = _('mailing list')
        verbose_name_plural = _('mailing lists')
        ordering = ('-id',)

    def __unicode__(self):
        return unicode(

class Newsletter(models.Model):
    title = models.CharField(
        help_text=_("Used on the e-mail's subject")
    html_content = models.TextField(_('HTML content'), blank=True)
    text_content = models.TextField(_('text content'), blank=True)
    mailing_list = models.ForeignKey(MailingList, verbose_name=_('mailing list'))
    sending_date = models.DateTimeField(
        _('sending date'),,
    status = models.CharField(

    class Meta:
        verbose_name = _('newsletter')
        verbose_name_plural = _('newsletters')
        ordering = ('-id',)

    def __unicode__(self):
        return unicode(self.title)

    def clean(self):
        if not self.html_content and not self.text_content:
            raise ValidationError(_('You must provide a HTML or text content!'))
        # Set the pub_date for published items if it hasn't been set already.
        if self.status == 'published' and self.pub_date is None:
            self.pub_date =

    def save(self, *args, **kwargs):
        if not self.text_content and self.html_content:
            self.text_content = _(
                'This message contains an HTML formatted message but your '
                'e-mail client does not support the display of HTML.'
        return super(Newsletter, self).save(*args, **kwargs)

    def send(self):
        subject = self.title
        text_content, html_content = self.text_content, self.html_content
        from_email = settings.DEFAULT_FROM_EMAIL

        self.status = 'sending'

        for recipient in self.mailing_list.subscribers.all():
            contact_status, created = ContactMailingStatus.objects.get_or_create(
                defaults={'status': 'sending'}

            # Do not send the same newsletter to the same recipient twice
            if contact_status.status in ('canceled', 'sent'):

            # Send mail
            datatuple = ((subject, text_content, html_content, from_email, []),)
                contact_status.status = 'sent'
                status = 'sent'
            except smtplib.SMTPException:
                contact_status.status = 'failed'

        self.status = 'sent'

class ContactMailingStatus(models.Model):
    contact = models.ForeignKey(
    newsletter = models.ForeignKey(
    status = models.CharField(

    class Meta:
        verbose_name = _('contact mailing status')
        verbose_name_plural = _('contact mailing statuses')
        ordering = ('-id',)

    def __unicode__(self):
        status = self.get_status_display()
        return u'"%s" to %s %s' % (self.newsletter,, status)
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.