Merge branch 'master' of github.com:brack3t/Djrill

This commit is contained in:
Kenneth Love
2012-02-28 14:27:33 -08:00
6 changed files with 222 additions and 0 deletions

37
djrill/mail/__init__.py Normal file
View File

@@ -0,0 +1,37 @@
from django.core.exceptions import ImproperlyConfigured
from django.core.mail import EmailMultiAlternatives
class DjrillMessage(EmailMultiAlternatives):
alternative_subtype = "mandrill"
def __init__(self, subject='', body='', from_email=None, to=None, bcc=None,
connection=None, attachments=None, headers=None, alternatives=None,
cc=None, tags=None, track_opens=True, track_clicks=True):
super(DjrillMessage, self).__init__(subject, body, from_email, to, bcc,
connection, attachments, headers, alternatives, cc)
self.tags = self._set_mandrill_tags(tags)
self.track_opens = track_opens
self.track_clicks = track_clicks
def _set_mandrill_tags(self, tags):
"""
Check that all tags are below 50 chars and that they do not start
with an underscore.
Raise ImproperlyConfigured if an underscore tag is passed in to
alert the user. Any tag over 50 chars is left out of the list.
"""
tag_list = []
for tag in tags:
if len(tag) <= 50 and not tag.startswith("_"):
tag_list.append(tag)
elif tag.startswith("_"):
raise ImproperlyConfigured(
"Tags starting with an underscore are reserved for "
"internal use and will cause errors with Mandill's API")
return tag_list

View File

View File

@@ -0,0 +1,131 @@
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.core.mail.backends.base import BaseEmailBackend
from django.core.mail.message import sanitize_address
from django.utils import simplejson as json
import requests
class DjrillBackend(BaseEmailBackend):
"""
Mandrill API Email Backend
"""
def __init__(self, fail_silently=False, **kwargs):
"""
Set the API key, API url and set the action url.
"""
super(DjrillBackend, self).__init__(**kwargs)
self.api_key = getattr(settings, "MANDRILL_API_KEY", None)
self.api_url = getattr(settings, "MANDRILL_API_URL", None)
self.connection = None
if not self.api_key:
raise ImproperlyConfigured("You have not set your mandrill api key "
"in the settings.py file.")
if not self.api_url:
raise ImproperlyConfigured("You have not added the Mandrill api "
"url to your settings.py")
self.api_action = self.api_url + "/messages/send.json"
self.api_verify = self.api_url + "/users/verify-sender.json"
def open(self, sender):
"""
"""
self.connection = None
valid_sender = requests.post(
self.api_verify, data={"key": self.api_key, "email": sender})
if valid_sender.status_code == 200:
data = json.loads(valid_sender.content)
if data["is_enabled"]:
self.connection = True
return True
else:
if not self.fail_silently:
raise
def send_messages(self, email_messages):
if not email_messages:
return
num_sent = 0
for message in email_messages:
self.open(message.from_email)
if not self.connection:
return
sent = self._send(message)
if sent:
num_sent += 1
return num_sent
def _send(self, message):
if not message.recipients():
return False
self.sender = sanitize_address(message.from_email, message.encoding)
recipients_list = [sanitize_address(addr, message.encoding)
for addr in message.recipients()]
from email.utils import parseaddr
self.recipients = [{"email": e, "name": n} for n,e in [
parseaddr(r) for r in recipients_list]]
self.msg_dict = self._build_standard_message_dict(message)
if getattr(message, "alternative_subtype", None):
if message.alternative_subtype == "mandrill":
if message.alternatives:
self._add_alternatives(message)
djrill_it = requests.post(self.api_action, data=json.dumps({
"key": self.api_key,
"message": self.msg_dict
}))
if djrill_it.status_code != 200:
if not self.fail_silently:
raise
return False
return True
def _build_standard_message_dict(self, message):
"""
Build standard message dict.
Builds the standard dict that Django's send_mail and send_mass_mail
use by default. Standard text email messages sent through Django will
still work through Mandrill.
"""
return {
"text": message.body,
"subject": message.subject,
"from_email": self.sender,
"from_name": "Devs - FIX ME",
"to": self.recipients
}
def _add_alternatives(self, message):
"""
There can be only one! ... alternative attachment.
Since mandrill does not accept image attachments or anything other
than HTML, the assumption is the only thing you are attaching is
the HTML output for your email.
"""
if len(message.alternatives) > 1:
raise ImproperlyConfigured(
"Mandrill only accepts plain text and html emails. Please "
"check the alternatives you have attached to your message.")
self.msg_dict.update({
"html": message.alternatives[0][0],
"tags": message.tags,
"track_opens": message.track_opens,
"track_clicks": message.track_clicks
})

0
djrill/models.py Normal file
View File

View File

@@ -0,0 +1,51 @@
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.test import TestCase
from djrill.mail import DjrillMessage
class DjrillMessageTests(TestCase):
def setUp(self):
self.subject = "Djrill baby djrill."
self.from_email = "test@example"
self.to = ["King Kong <kingkong@example.com>",
"Cheetah <cheetah@example.com", "bubbles@example.com"]
self.text_content = "Wonderful fallback text content."
self.html_content = "<h1>That's a nice HTML email right there.</h1>"
self.tags = ["track", "this"]
def test_djrill_message_success(self):
msg = DjrillMessage(self.subject, self.text_content, self.from_email,
self.to, tags=self.tags)
self.assertIsInstance(msg, DjrillMessage)
self.assertEqual(msg.body, self.text_content)
self.assertEqual(msg.recipients(), self.to)
self.assertEqual(msg.tags, self.tags)
def test_djrill_message_html_success(self):
msg = DjrillMessage(self.subject, self.text_content, self.from_email,
self.to, tags=self.tags)
msg.attach_alternative(self.html_content, "text/html")
self.assertEqual(msg.alternatives[0][0], self.html_content)
def test_djrill_message_tag_failure(self):
with self.assertRaises(ImproperlyConfigured):
DjrillMessage(self.subject, self.text_content, self.from_email,
self.to, tags=["_fail"])
def test_djrill_message_tag_skip(self):
"""
Test that tags over 50 chars are not included in the tags list.
"""
tags = ["works", "awesomesauce",
"iwilltestmycodeiwilltestmycodeiwilltestmycodeiwilltestmycode"]
msg = DjrillMessage(self.subject, self.text_content, self.from_email,
self.to, tags=tags)
self.assertIsInstance(msg, DjrillMessage)
self.assertIn(tags[0], msg.tags)
self.assertIn(tags[1], msg.tags)
self.assertNotIn(tags[2], msg.tags)

View File

@@ -24,6 +24,9 @@ DATABASES = {
MANDRILL_API_KEY = None MANDRILL_API_KEY = None
MANDRILL_API_URL = "http://mandrillapp.com/api/1.0" MANDRILL_API_URL = "http://mandrillapp.com/api/1.0"
#EMAIL BACKEND
EMAIL_BACKEND = "djrill.mail.backends.djrill.DjrillBackend"
# Local time zone for this installation. Choices can be found here: # Local time zone for this installation. Choices can be found here:
# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name # http://en.wikipedia.org/wiki/List_of_tz_zones_by_name