September 24, 2008

Sending HTML emails to multiple subscribers via Django

Filed under: django — Tags: , , — Bart @ 4:38 pm

(Update: Please note I do not advocate spamming or any tomfoolery at all. See the comments below for some great discussion on sending out bulk emails correctly via setting up your DNS and SMTP Servers correctly)

Today I had the fun little project of building a very simple message sending system in Django that would fetch emails from a database of subscribers, check for the latest message in the queue, and send it out.

Sounds easy? Well yes, it is. But there’s a few things that Django can do to make the email sending much smarter.

First off, sending HTML emails in Django requires you to set an alternate content type. This is easily done using the django.core.mail.EmailMultiAlternatives class which is very similar to using the EmailMessage class but provides a few more options for HTML emails. Here’s a simple code snippet using this:

subject, from_email, to = ‘Say Hello to our new website!’, ’service@mycompany.com’, 
                                          ’someuser@gmail.com’
text_content = ‘This is an important message.’
html_content = ‘<p>This is an <strong>important</strong> message.</p>’
msg = EmailMultiAlternatives(subject, text_content, from_email, [to])
msg.attach_alternative(html_content, “text/html”)
msg.send()

This very simple example sends an email to someuser@gmail.com with an alternative minetype for html. What this allows is for people who have HTML-enabled email clients they receive the full on HTML view, while people who are stuck with text based emails simply get a nice clean cut text email instead of html garble.

Django offers another class that makes it extremely efficient on sending emails to mass amounts of users. Now there is little documentation on this so I do not know how far you can stretch this (hundreds, or thousands of emails?) but it has worked well for me.

It is the SMTPConnection class also found in django.core.mail. With it, you can store all your EmailMessage()’s or your EmailMultiAlternatives()’s in a list of data and then send them all using one single connection instead of re-connecting each time. This is similar to using send_mass_mail but that is just a thin wrapper that does not support alternative mimetypes like HTML and other goodies. Here’s a simple code snipper:

 

# If you do not provide any connection settings, it uses the default found in settings.py
connection = SMTPConnection()
connection.send_messages(messages) # messages can be a list of EmailMessage objects

So those are two great classes that make email sending just that much simpler in Django. How would you put this all together? Here’s a simple example script that fetches an email message from a model named Message, some subscribers, and then sends out a mass email to them. In this script, Message is a model that holds the actual HTML email and Subscribers is a list of our subscribers. To keep it simple, we only work with their email

from django.core.mail import  EmailMultiAlternatives, SMTPConnection
from mysite.email_app.models import Subscriber, Message
message = Message.objects.order_by('-id')[:1][0] # Fetch latest message in our list of emails
if not message.is_sent:
      subscribers = Subscriber.objects.all()
      emails_to_send = []
      for s in subscribers:
           msg = EmailMultiAlternatives(message.subject, message.body_text, 'myemail@foo.com', 
                                                                     [s.email])
           # Attach the html version of our email to the email
           msg.attach_alternative(message.body_html, "text/html")
           emails_to_send.append( msg )
      # Setup a single SMTPConnection to send all emails instead of re-connecting each time
      connection = SMTPConnection()
      connection.send_messages(emails_to_send)
      message.is_sent = True
      message.save()

That’s just a very simple example and if you know any ounce of Django I hope you can understand it. You could also add something like a send_time to your Message model and then run a daily cron script to check if an email has to go out to your user base. This is basically the setup I have now at the office and it works great.

 

For a full reference, see: Django | Sending e-amil

 

 

 

 

May 5, 2007

contact info

Filed under: aboutme, contact — Tags: , , , , , — Bart @ 5:25 pm

(more…)

Powered By WordPress