Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion postmark/__init__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
VERSION = (0, 1, 6, "final", 0)
VERSION = (0, 2, 1, "final", 0)


def get_version():
Expand Down
144 changes: 63 additions & 81 deletions postmark/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -1,86 +1,68 @@
# encoding: utf-8
import datetime
from south.db import db
from south.v2 import SchemaMigration
from django.db import models
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

class Migration(SchemaMigration):
from django.db import models, migrations

def forwards(self, orm):

# Adding model 'EmailMessage'
db.create_table('postmark_emailmessage', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('message_id', self.gf('django.db.models.fields.CharField')(max_length=40)),
('submitted_at', self.gf('django.db.models.fields.DateTimeField')()),
('status', self.gf('django.db.models.fields.CharField')(max_length=150)),
('to', self.gf('django.db.models.fields.CharField')(max_length=150)),
('to_type', self.gf('django.db.models.fields.CharField')(max_length=3)),
('sender', self.gf('django.db.models.fields.CharField')(max_length=150)),
('reply_to', self.gf('django.db.models.fields.CharField')(max_length=150)),
('subject', self.gf('django.db.models.fields.CharField')(max_length=150)),
('tag', self.gf('django.db.models.fields.CharField')(max_length=25)),
('text_body', self.gf('django.db.models.fields.TextField')()),
('html_body', self.gf('django.db.models.fields.TextField')()),
('headers', self.gf('django.db.models.fields.TextField')()),
('attachments', self.gf('django.db.models.fields.TextField')()),
))
db.send_create_signal('postmark', ['EmailMessage'])

# Adding model 'EmailBounce'
db.create_table('postmark_emailbounce', (
('id', self.gf('django.db.models.fields.PositiveIntegerField')(primary_key=True)),
('message', self.gf('django.db.models.fields.related.ForeignKey')(related_name='bounces', to=orm['postmark.EmailMessage'])),
('inactive', self.gf('django.db.models.fields.BooleanField')(default=False)),
('can_activate', self.gf('django.db.models.fields.BooleanField')(default=False)),
('type', self.gf('django.db.models.fields.CharField')(max_length=100)),
('description', self.gf('django.db.models.fields.TextField')()),
('details', self.gf('django.db.models.fields.TextField')()),
('bounced_at', self.gf('django.db.models.fields.DateTimeField')()),
('_order', self.gf('django.db.models.fields.IntegerField')(default=0)),
))
db.send_create_signal('postmark', ['EmailBounce'])
class Migration(migrations.Migration):

dependencies = [
]

def backwards(self, orm):

# Deleting model 'EmailMessage'
db.delete_table('postmark_emailmessage')

# Deleting model 'EmailBounce'
db.delete_table('postmark_emailbounce')


models = {
'postmark.emailbounce': {
'Meta': {'ordering': "('_order',)", 'object_name': 'EmailBounce'},
'_order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'bounced_at': ('django.db.models.fields.DateTimeField', [], {}),
'can_activate': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'description': ('django.db.models.fields.TextField', [], {}),
'details': ('django.db.models.fields.TextField', [], {}),
'id': ('django.db.models.fields.PositiveIntegerField', [], {'primary_key': 'True'}),
'inactive': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'message': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'bounces'", 'to': "orm['postmark.EmailMessage']"}),
'type': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'postmark.emailmessage': {
'Meta': {'ordering': "['-submitted_at']", 'object_name': 'EmailMessage'},
'attachments': ('django.db.models.fields.TextField', [], {}),
'headers': ('django.db.models.fields.TextField', [], {}),
'html_body': ('django.db.models.fields.TextField', [], {}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'message_id': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
'reply_to': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
'sender': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
'status': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
'subject': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
'submitted_at': ('django.db.models.fields.DateTimeField', [], {}),
'tag': ('django.db.models.fields.CharField', [], {'max_length': '25'}),
'text_body': ('django.db.models.fields.TextField', [], {}),
'to': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
'to_type': ('django.db.models.fields.CharField', [], {'max_length': '3'})
}
}

complete_apps = ['postmark']
operations = [
migrations.CreateModel(
name='EmailBounce',
fields=[
('id', models.PositiveIntegerField(serialize=False, primary_key=True)),
('inactive', models.BooleanField(verbose_name='Inactive')),
('can_activate', models.BooleanField(verbose_name='Can Activate')),
('type', models.CharField(max_length=100, verbose_name='Type', choices=[(b'HardBounce', 'Hard Bounce'), (b'Transient', 'Transient'), (b'Unsubscribe', 'Unsubscribe'), (b'Subscribe', 'Subscribe'), (b'AutoResponder', 'Auto Responder'), (b'AddressChange', 'Address Change'), (b'DnsError', 'DNS Error'), (b'SpamNotification', 'Spam Notification'), (b'OpenRelayTest', 'Open Relay Test'), (b'Unknown', 'Unknown'), (b'SoftBounce', 'Soft Bounce'), (b'VirusNotification', 'Virus Notification'), (b'ChallengeVerification', 'Challenge Verification'), (b'BadEmailAddress', 'Bad Email Address'), (b'SpamComplaint', 'Spam Complaint'), (b'ManuallyDeactivated', 'Manually Deactivated'), (b'Unconfirmed', 'Unconfirmed'), (b'Blocked', 'Blocked')])),
('description', models.TextField(verbose_name='Description')),
('details', models.TextField(verbose_name='Details')),
('bounced_at', models.DateTimeField(verbose_name='Bounced At')),
],
options={
'ordering': ['-bounced_at'],
'get_latest_by': 'bounced_at',
'verbose_name': 'email bounce',
'verbose_name_plural': 'email bounces',
},
bases=(models.Model,),
),
migrations.CreateModel(
name='EmailMessage',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('message_id', models.CharField(max_length=40, verbose_name='Message ID')),
('submitted_at', models.DateTimeField(verbose_name='Submitted At')),
('status', models.CharField(max_length=150, verbose_name='Status')),
('to', models.CharField(max_length=150, verbose_name='To')),
('to_type', models.CharField(max_length=3, verbose_name='Type', choices=[(b'to', 'Recipient'), (b'cc', 'Carbon Copy'), (b'bcc', 'Blind Carbon Copy')])),
('sender', models.CharField(max_length=150, verbose_name='Sender')),
('reply_to', models.CharField(max_length=150, verbose_name='Reply To')),
('subject', models.CharField(max_length=150, verbose_name='Subject')),
('tag', models.CharField(max_length=150, verbose_name='Tag')),
('text_body', models.TextField(verbose_name='Text Body')),
('html_body', models.TextField(verbose_name='HTML Body')),
('headers', models.TextField(verbose_name='Headers')),
('attachments', models.TextField(verbose_name='Attachments')),
],
options={
'ordering': ['-submitted_at'],
'get_latest_by': 'submitted_at',
'verbose_name': 'email message',
'verbose_name_plural': 'email messages',
},
bases=(models.Model,),
),
migrations.AddField(
model_name='emailbounce',
name='message',
field=models.ForeignKey(related_name='bounces', verbose_name='Message', to='postmark.EmailMessage'),
preserve_default=True,
),
migrations.AlterOrderWithRespectTo(
name='emailbounce',
order_with_respect_to='message',
),
]
26 changes: 26 additions & 0 deletions postmark/migrations/0002_auto_20141028_2212.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations


class Migration(migrations.Migration):

dependencies = [
('postmark', '0001_initial'),
]

operations = [
migrations.AlterField(
model_name='emailbounce',
name='can_activate',
field=models.BooleanField(default=False, verbose_name='Can Activate'),
preserve_default=True,
),
migrations.AlterField(
model_name='emailbounce',
name='inactive',
field=models.BooleanField(default=False, verbose_name='Inactive'),
preserve_default=True,
),
]
61 changes: 30 additions & 31 deletions postmark/models.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
from django.utils.translation import ugettext_lazy as _
from django.dispatch import receiver
from dateutil.parser import parse as parsedatetime
from django.db import models
from django.dispatch import receiver
from django.utils.translation import ugettext_lazy as _
from itertools import izip_longest
from datetime import datetime
from pytz import timezone
import pytz

from postmark.signals import post_send

Expand Down Expand Up @@ -37,77 +35,78 @@
("Blocked", _("Blocked")),
)


class EmailMessage(models.Model):
message_id = models.CharField(_("Message ID"), max_length=40)
submitted_at = models.DateTimeField(_("Submitted At"))
status = models.CharField(_("Status"), max_length=150)

to = models.CharField(_("To"), max_length=150)
to_type = models.CharField(_("Type"), max_length=3, choices=TO_CHOICES)

sender = models.CharField(_("Sender"), max_length=150)
reply_to = models.CharField(_("Reply To"), max_length=150)
subject = models.CharField(_("Subject"), max_length=150)
tag = models.CharField(_("Tag"), max_length=150)
text_body = models.TextField(_("Text Body"))
html_body = models.TextField(_("HTML Body"))

headers = models.TextField(_("Headers"))
attachments = models.TextField(_("Attachments"))

def __unicode__(self):
return u"%s" % (self.message_id,)

class Meta:
verbose_name = _("email message")
verbose_name_plural = _("email messages")

get_latest_by = "submitted_at"
ordering = ["-submitted_at"]


class EmailBounce(models.Model):
id = models.PositiveIntegerField(primary_key=True)
message = models.ForeignKey(EmailMessage, related_name="bounces", verbose_name=_("Message"))

inactive = models.BooleanField(_("Inactive"))
can_activate = models.BooleanField(_("Can Activate"))

message = models.ForeignKey(
EmailMessage, related_name="bounces", verbose_name=_("Message"))

inactive = models.BooleanField(_("Inactive"), default=False)
can_activate = models.BooleanField(_("Can Activate"), default=False)

type = models.CharField(_("Type"), max_length=100, choices=BOUNCE_TYPES)
description = models.TextField(_("Description"))
details = models.TextField(_("Details"))

bounced_at = models.DateTimeField(_("Bounced At"))

def __unicode__(self):
return u"Bounce: %s" % (self.message.to,)

class Meta:
verbose_name = _("email bounce")
verbose_name_plural = _("email bounces")

order_with_respect_to = "message"
get_latest_by = "bounced_at"
ordering = ["-bounced_at"]


@receiver(post_send)
def sent_message(sender, **kwargs):
msg = kwargs["message"]
resp = kwargs["response"]

for recipient in (
list(izip_longest(msg["To"].split(","), [], fillvalue='to')) +
list(izip_longest(msg.get("Cc", "").split(","), [], fillvalue='cc')) +
list(izip_longest(msg.get("Bcc", "").split(","), [], fillvalue='bcc'))):

list(izip_longest(msg.get("Bcc", "").split(","), [], fillvalue='bcc'))
):

if not recipient[0]:
continue

timestamp, tz = resp["SubmittedAt"].rsplit("+", 1)
tz_offset = int(tz.split(":", 1)[0])
tz = timezone("Etc/GMT%s%d" % ("+" if tz_offset >= 0 else "-", tz_offset))
submitted_at = tz.localize(datetime.strptime(timestamp[:26], POSTMARK_DATETIME_STRING)).astimezone(pytz.utc)



submitted_at = parsedatetime(resp['SubmittedAt'])

emsg = EmailMessage(
message_id=resp["MessageID"],
submitted_at=submitted_at,
Expand All @@ -123,4 +122,4 @@ def sent_message(sender, **kwargs):
headers=msg.get("Headers", ""),
attachments=msg.get("Attachments", "")
)
emsg.save()
emsg.save()
86 changes: 86 additions & 0 deletions postmark/south_migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# encoding: 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 'EmailMessage'
db.create_table('postmark_emailmessage', (
('id', self.gf('django.db.models.fields.AutoField')(primary_key=True)),
('message_id', self.gf('django.db.models.fields.CharField')(max_length=40)),
('submitted_at', self.gf('django.db.models.fields.DateTimeField')()),
('status', self.gf('django.db.models.fields.CharField')(max_length=150)),
('to', self.gf('django.db.models.fields.CharField')(max_length=150)),
('to_type', self.gf('django.db.models.fields.CharField')(max_length=3)),
('sender', self.gf('django.db.models.fields.CharField')(max_length=150)),
('reply_to', self.gf('django.db.models.fields.CharField')(max_length=150)),
('subject', self.gf('django.db.models.fields.CharField')(max_length=150)),
('tag', self.gf('django.db.models.fields.CharField')(max_length=25)),
('text_body', self.gf('django.db.models.fields.TextField')()),
('html_body', self.gf('django.db.models.fields.TextField')()),
('headers', self.gf('django.db.models.fields.TextField')()),
('attachments', self.gf('django.db.models.fields.TextField')()),
))
db.send_create_signal('postmark', ['EmailMessage'])

# Adding model 'EmailBounce'
db.create_table('postmark_emailbounce', (
('id', self.gf('django.db.models.fields.PositiveIntegerField')(primary_key=True)),
('message', self.gf('django.db.models.fields.related.ForeignKey')(related_name='bounces', to=orm['postmark.EmailMessage'])),
('inactive', self.gf('django.db.models.fields.BooleanField')(default=False)),
('can_activate', self.gf('django.db.models.fields.BooleanField')(default=False)),
('type', self.gf('django.db.models.fields.CharField')(max_length=100)),
('description', self.gf('django.db.models.fields.TextField')()),
('details', self.gf('django.db.models.fields.TextField')()),
('bounced_at', self.gf('django.db.models.fields.DateTimeField')()),
('_order', self.gf('django.db.models.fields.IntegerField')(default=0)),
))
db.send_create_signal('postmark', ['EmailBounce'])


def backwards(self, orm):

# Deleting model 'EmailMessage'
db.delete_table('postmark_emailmessage')

# Deleting model 'EmailBounce'
db.delete_table('postmark_emailbounce')


models = {
'postmark.emailbounce': {
'Meta': {'ordering': "('_order',)", 'object_name': 'EmailBounce'},
'_order': ('django.db.models.fields.IntegerField', [], {'default': '0'}),
'bounced_at': ('django.db.models.fields.DateTimeField', [], {}),
'can_activate': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'description': ('django.db.models.fields.TextField', [], {}),
'details': ('django.db.models.fields.TextField', [], {}),
'id': ('django.db.models.fields.PositiveIntegerField', [], {'primary_key': 'True'}),
'inactive': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
'message': ('django.db.models.fields.related.ForeignKey', [], {'related_name': "'bounces'", 'to': "orm['postmark.EmailMessage']"}),
'type': ('django.db.models.fields.CharField', [], {'max_length': '100'})
},
'postmark.emailmessage': {
'Meta': {'ordering': "['-submitted_at']", 'object_name': 'EmailMessage'},
'attachments': ('django.db.models.fields.TextField', [], {}),
'headers': ('django.db.models.fields.TextField', [], {}),
'html_body': ('django.db.models.fields.TextField', [], {}),
'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
'message_id': ('django.db.models.fields.CharField', [], {'max_length': '40'}),
'reply_to': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
'sender': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
'status': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
'subject': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
'submitted_at': ('django.db.models.fields.DateTimeField', [], {}),
'tag': ('django.db.models.fields.CharField', [], {'max_length': '25'}),
'text_body': ('django.db.models.fields.TextField', [], {}),
'to': ('django.db.models.fields.CharField', [], {'max_length': '150'}),
'to_type': ('django.db.models.fields.CharField', [], {'max_length': '3'})
}
}

complete_apps = ['postmark']
Empty file.
Loading