Skip to content

Instantly share code, notes, and snippets.

@fish2000
Created October 16, 2010 10:51
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save fish2000/629663 to your computer and use it in GitHub Desktop.
Save fish2000/629663 to your computer and use it in GitHub Desktop.
Database email queue
#!/usr/bin/env python
# encoding: utf-8
import sys, os, getopt
from django.core.management import setup_environ
import settings
setup_environ(settings)
from django.db.models import Q
from YOUR_SITE.models import QueuedEmail
class Usage(Exception):
def __init__(self, msg):
self.msg = msg
def main(argv=None):
if argv is None:
argv = sys.argv
try:
try:
opts, args = getopt.getopt(argv[1:], "hv", ["help", "verbose"])
except getopt.error, msg:
raise Usage(msg)
for option, value in opts:
if option in ("-v", "--verbose"):
verbose = True
if option in ("-h", "--help"):
raise Usage("QueuedEmail queue flush tool. Use -v for verbose.")
except Usage, err:
print >> sys.stderr, sys.argv[0].split("/")[-1] + ": " + str(err.msg)
print >> sys.stderr, "\t for help use --help"
return 2
mailqueue = FSQueuedEmail.objects.filter(
Q(status=0) & (Q(to__isnull=False) | Q(toaddress__isnull=False) & Q(subject__isnull=False))
)
if verbose:
print "###\t Mail queue contains %s items to be sent.\n" % len(mailqueue)
for qm in mailqueue:
if verbose:
print "###\t Sending message..."
print "---\t TO:\t\t\t %s" % qm.to
print "---\t TOADDRESS:\t\t %s" % qm.toaddress
print "---\t SUBJECT:\t\t %s" % qm.subject
# output will be 1 if sending was successful
# messages will be saved to the DB with the
# same number for their status.
if qm.sendit() == 1:
if verbose:
print "---\t Mail sent OK\n"
else:
print "###\t MAIL FAIL\n"
if __name__ == "__main__":
sys.exit(main())
from django.core.mail import send_mail
import smtplib
class QueuedEmail(models.Model):
"""
DATABASE EMAIL QUEUE --
QueuedEmail stashes your sites' messages in a table, so you don't have to wait on
synchronous calls to django.core.mail.send_mail. Mail stays in the database after
sending for as long as you leave them there, which provides a paper trail and
a basis for analytics. I wrote it for use with an invitation-only site, where
the flushqueuedemail.py script is run with a cron job.
USAGE EXAMPLE --
This simple bit here will queue a new message from within any python code:
def some_view_function(request):
(...)
invitation = FSQueuedEmail(
toaddress=invite.sentto,
subject="Welcome",
body=u'''
Hello,
Welcome to the site, %s. Your username is %s.
Regards,
The Management
''' % (
request.user.get_full_name(),
request.user.username,
)
)
invitation.save()
(...)
You can pass either an instance of django.contrib.auth.models.User in the 'to' param, or use
a string with an email address in it with 'toaddress'. One can easily integrate templating,
or compose emails programmatically, or embed the email text for quick development and testing.
Add this model to your site, and flush the queue with the attached command-line tool (or write your
own, it's like one query and one loop, and hey it could be smaller.)
Enjoy!
-fish2000
"""
class Meta:
abstract = False
verbose_name = "queued email message"
verbose_name_plural = "queued email messages"
status = models.IntegerField(verbose_name="Status",
editable=True,
null=False,
default=0,
choices=(
(-1, 'SMTP Fail'),
(0, 'Queued'),
(1, 'Sent OK'),
(2, 'Unexpected Error'),
))
createdate = models.DateTimeField('Created on',
default=datetime.now,
blank=True,
editable=False)
modifydate = models.DateTimeField('Last modified on',
default=datetime.now,
blank=True,
editable=False)
senddate = models.DateTimeField('Send after',
default=datetime.now,
blank=True,
editable=True)
subject = models.CharField(verbose_name="Subject",
default="",
unique=False,
blank=True,
max_length=255)
body = models.TextField(verbose_name="Body",
default="",
unique=False,
blank=True)
to = models.ForeignKey(User,
default=None,
unique=False,
blank=True,
null=True,
verbose_name="To (User)")
toaddress = models.EmailField(verbose_name="To (Additional address or addresses)",
default=None,
unique=False,
blank=True,
null=True,
max_length=255)
def save(self, force_insert=False, force_update=False):
self.modifydate = datetime.now()
super(QueuedEmail, self).save(force_insert, force_update)
def sendit(self):
if self.senddate < datetime.now():
if self.subject and self.body:
if self.toaddress:
try:
self.status = send_mail(
# one can insert [sitename] or somesuch
# at the start of the subject here
"%s" % self.subject,
self.body,
settings.EMAIL_HOST_USER,
[self.toaddress]
)
except smtplib.SMTPException:
self.status = -1
self.save()
else:
self.save()
elif self.to and self.to.email:
try:
self.status = send_mail(
"%s" % self.subject,
self.body,
settings.EMAIL_HOST_USER,
[self.to.email]
)
except smtplib.SMTPException:
self.status = -1
self.save()
else:
self.save()
return self.status
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment