--- /dev/null
+from django.contrib import admin
+
+from models import QueuedMail
+
+admin.site.register(QueuedMail)
--- /dev/null
+# Script to send off all queued email.
+#
+# This script is intended to be run frequently from cron. We queue things
+# up in the db so that they get automatically rolled back as necessary,
+# but once we reach this point we're just going to send all of them one
+# by one.
+#
+from django.core.management.base import BaseCommand, CommandError
+from django.db import connection
+
+import smtplib
+
+from hamnadmin.mailqueue.models import QueuedMail
+
+class Command(BaseCommand):
+ help = 'Send queued mail'
+
+ def handle(self, *args, **options):
+ # Grab advisory lock, if available. Lock id is just a random number
+ # since we only need to interlock against ourselves. The lock is
+ # automatically released when we're done.
+ curs = connection.cursor()
+ curs.execute("SELECT pg_try_advisory_lock(72181378)")
+ if not curs.fetchall()[0][0]:
+ raise CommandException("Failed to get advisory lock, existing send_queued_mail process stuck?")
+
+ for m in QueuedMail.objects.all():
+ # Yes, we do a new connection for each run. Just because we can.
+ # If it fails we'll throw an exception and just come back on the
+ # next cron job. And local delivery should never fail...
+ smtp = smtplib.SMTP("localhost")
+ smtp.sendmail(m.sender, m.receiver, m.fullmsg.encode('utf-8'))
+ smtp.close()
+ m.delete()
--- /dev/null
+# -*- coding: utf-8 -*-
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='QueuedMail',
+ fields=[
+ ('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
+ ('sender', models.EmailField(max_length=100)),
+ ('receiver', models.EmailField(max_length=100)),
+ ('fullmsg', models.TextField()),
+ ],
+ ),
+ ]
--- /dev/null
+from django.db import models
+
+class QueuedMail(models.Model):
+ sender = models.EmailField(max_length=100, null=False, blank=False)
+ receiver = models.EmailField(max_length=100, null=False, blank=False)
+ # We store the raw MIME message, so if there are any attachments or
+ # anything, we just push them right in there!
+ fullmsg = models.TextField(null=False, blank=False)
+
+ def __unicode__(self):
+ return "%s: %s -> %s" % (self.pk, self.sender, self.receiver)
--- /dev/null
+from email.mime.text import MIMEText
+from email.mime.multipart import MIMEMultipart
+from email.mime.nonmultipart import MIMENonMultipart
+from email.Utils import formatdate
+from email import encoders
+
+from models import QueuedMail
+
+def send_simple_mail(sender, receiver, subject, msgtxt, attachments=None, bcc=None, sendername=None, receivername=None):
+ # attachment format, each is a tuple of (name, mimetype,contents)
+ # content should be *binary* and not base64 encoded, since we need to
+ # use the base64 routines from the email library to get a properly
+ # formatted output message
+ msg = MIMEMultipart()
+ msg['Subject'] = subject
+ if receivername:
+ msg['To'] = u'{0} <{1}>'.format(receivername, receiver)
+ else:
+ msg['To'] = receiver
+ if sendername:
+ msg['From'] = u'{0} <{1}>'.format(sendername, sender)
+ else:
+ msg['From'] = sender
+ msg['Date'] = formatdate(localtime=True)
+
+ msg.attach(MIMEText(msgtxt, _charset='utf-8'))
+
+ if attachments:
+ for filename, contenttype, content in attachments:
+ main,sub = contenttype.split('/')
+ part = MIMENonMultipart(main,sub)
+ part.set_payload(content)
+ part.add_header('Content-Disposition', 'attachment; filename="%s"' % filename)
+ encoders.encode_base64(part)
+ msg.attach(part)
+
+
+ # Just write it to the queue, so it will be transactionally rolled back
+ QueuedMail(sender=sender, receiver=receiver, fullmsg=msg.as_string()).save()
+ # Any bcc is just entered as a separate email
+ if bcc:
+ QueuedMail(sender=sender, receiver=bcc, fullmsg=msg.as_string()).save()
+
+def send_mail(sender, receiver, fullmsg):
+ # Send an email, prepared as the full MIME encoded mail already
+ QueuedMail(sender=sender, receiver=receiver, fullmsg=fullmsg).save()
'django.contrib.sites',
'django.contrib.staticfiles',
'hamnadmin.register',
+ 'hamnadmin.mailqueue',
'django.contrib.admin',
)