Skip to content

Commit

Permalink
Merge branch 'release/v0.4.2'
Browse files Browse the repository at this point in the history
  • Loading branch information
RyanBalfanz committed Mar 25, 2012
2 parents c86bc6e + 41e800d commit 5cd7c1d
Show file tree
Hide file tree
Showing 15 changed files with 401 additions and 63 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -2,6 +2,7 @@
*.pyc
*.DS_Store
secret.sh
docs/_build/*
build/*
dist/*
django_sendgrid.egg-info/*
1 change: 1 addition & 0 deletions README.rst
Expand Up @@ -45,3 +45,4 @@ Additional Information
- https://docs.djangoproject.com/en/1.3/topics/email/
- http://ryanbalfanz.github.com/django-sendgrid/
- http://pypi.python.org/pypi/django-sendgrid
- http://djangopackages.com/packages/p/django-sendgrid/
38 changes: 34 additions & 4 deletions example_project/main/templates/main/send_email.html
Expand Up @@ -3,11 +3,41 @@
<head>
<meta charset="UTF-8">
<title>django-sendgrid example project</title>
<style type="text/css">
body {
padding-top: 60px;
padding-bottom: 40px;
}
</style>
<link rel="stylesheet" href="http://twitter.github.com/bootstrap/assets/css/bootstrap.css" type="text/css" media="screen" charset="utf-8">
<!-- http://davidwalsh.name/blank-favicon -->
<link href="data:image/x-icon;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQEAYAAABPYyMiAAAABmJLR0T///////8JWPfcAAAACXBIWXMAAABIAAAASABGyWs+AAAAF0lEQVRIx2NgGAWjYBSMglEwCkbBSAcACBAAAeaR9cIAAAAASUVORK5CYII=" rel="icon" type="image/x-icon" />
</head>
<body>
<form action="/sendgrid/" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
<div class="navbar navbar-fixed-top">
<div class="navbar-inner">
<div class="container">
<a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</a>
<a class="brand" href="#">django-sendgrid</a>
<div class="nav-collapse">
<ul class="nav">
<li><a href="https://github.com/RyanBalfanz/django-sendgrid">Github</a></li>
<li><a href="http://pypi.python.org/pypi/django-sendgrid">PyPI</a></li>
<li><a href="http://djangopackages.com/packages/p/django-sendgrid/">django-packages</a></li>
</ul>
</div><!--/.nav-collapse -->
</div>
</div>
</div>
<div class="container">
<form action="/sendgrid/" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Send" />
</form>
</div>
</body>
</html>
5 changes: 5 additions & 0 deletions example_project/settings.py
Expand Up @@ -169,3 +169,8 @@
SENDGRID_EMAIL_PORT = 587
SENDGRID_EMAIL_USERNAME = os.getenv("SENDGRID_EMAIL_USERNAME")
SENDGRID_EMAIL_PASSWORD = os.getenv("SENDGRID_EMAIL_PASSWORD")

try:
from settings_local import *
except ImportError:
pass
1 change: 1 addition & 0 deletions example_project/templates/404.html
@@ -0,0 +1 @@
404 Error
1 change: 1 addition & 0 deletions example_project/templates/500.html
@@ -0,0 +1 @@
500 Error
5 changes: 2 additions & 3 deletions example_project/urls.py
Expand Up @@ -6,9 +6,8 @@

urlpatterns = patterns('',
# Examples:
url(r'^$', include('example_project.main.urls')),
url(r'^sendgrid/$', include('example_project.main.urls')),

url(r'^$', 'django.views.generic.simple.redirect_to', {'url': '/sendgrid/'}, name='home'),
url(r"^sendgrid/", include("example_project.main.urls")),
# Uncomment the admin/doc line below to enable admin documentation:
# url(r'^admin/doc/', include('django.contrib.admindocs.urls')),

Expand Down
5 changes: 5 additions & 0 deletions requirements.txt
@@ -0,0 +1,5 @@
Django==1.3.1
distribute==0.6.24
virtualenv==1.6.4
virtualenvwrapper==2.10.1
wsgiref==0.1.2
6 changes: 0 additions & 6 deletions requirments.txt

This file was deleted.

2 changes: 1 addition & 1 deletion sendgrid/__init__.py
@@ -1,6 +1,6 @@
"""django-sendgrid"""

VERSION = (0, 4, 1)
VERSION = (0, 4, 2)

__version__ = ".".join(map(str, VERSION[0:3])) + "".join(VERSION[3:])
__author__ = "Ryan Balfanz"
Expand Down
11 changes: 7 additions & 4 deletions sendgrid/backends.py
@@ -1,6 +1,7 @@
import logging

from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
from django.core.mail.backends.smtp import EmailBackend


Expand All @@ -11,8 +12,7 @@

logger = logging.getLogger(__name__)


def check_settings():
def check_settings(fail_silently=False):
"""
Checks that the required settings are available.
"""
Expand All @@ -29,17 +29,20 @@ def check_settings():
if not value:
logger.warn("{k} is not set".format(k=key))
allOk = False
if not fail_silently:
raise ImproperlyConfigured("{k} was not found".format(k=key))

return allOk


class SendGridEmailBackend(EmailBackend):
"""
A wrapper that manages the SendGrid SMTP network connection.
"""
def __init__(self, host=None, port=None, username=None, password=None, use_tls=None, fail_silently=False, **kwargs):
if not check_settings():
raise ValueError("A required setting was not found")
logger.exception("A required setting was not found")

super(SendGridEmailBackend, self).__init__(
host=SENDGRID_EMAIL_HOST,
port=SENDGRID_EMAIL_PORT,
Expand Down
123 changes: 98 additions & 25 deletions sendgrid/message.py
@@ -1,38 +1,32 @@
from __future__ import absolute_import

# import datetime
import logging
import json
import time
import uuid
try:
import simplejson as json
except ImportError:
import json

from django.conf import settings
from django.core import mail
from django.core.mail.message import EmailMessage
from django.core.mail.message import EmailMultiAlternatives

# django-sendgrid imports
from header import SmtpApiHeader
from mail import get_sendgrid_connection
from signals import sendgrid_email_sent
from .header import SmtpApiHeader
from .mail import get_sendgrid_connection
from .signals import sendgrid_email_sent


logger = logging.getLogger(__name__)


class SendGridEmailMessage(EmailMessage):
class SendGridEmailMessageMixin:
"""
Adapts Django's ``EmailMessage`` for use with SendGrid.
>>> from sendgrid.message import SendGridEmailMessage
>>> myEmail = "rbalfanz@gmail.com"
>>> mySendGridCategory = "django-sendgrid"
>>> e = SendGridEmailMessage("Subject", "Message", myEmail, [myEmail], headers={"Reply-To": myEmail})
>>> e.sendgrid_headers.setCategory(mySendGridCategory)
>>> response = e.send()
Adds support for SendGrid features.
"""
sendgrid_headers = SmtpApiHeader()

def __init__(self, *args, **kwargs):
"""
Initialize the object.
"""
super(SendGridEmailMessage, self).__init__(*args, **kwargs)

def _update_headers_with_sendgrid_headers(self):
"""
Updates the existing headers to include SendGrid headers.
Expand All @@ -43,28 +37,107 @@ def _update_headers_with_sendgrid_headers(self):
"X-SMTPAPI": self.sendgrid_headers.asJSON()
}
self.extra_headers.update(additionalHeaders)

logging.debug(str(self.extra_headers))

return self.extra_headers

def _update_unique_args(self, uniqueArgs):
"""docstring for _update_unique_args"""
# assert self.unique_args is None, self.unique_args
self.sendgrid_headers.setUniqueArgs(uniqueArgs)

return self.unique_args

def update_headers(self, *args, **kwargs):
"""
Updates the headers.
"""
return self._update_headers_with_sendgrid_headers(*args, **kwargs)

def send(self, *args, **kwargs):
"""Sends the email message."""
def get_category(self):
"""docstring for get_category"""
return self.sendgrid_headers.data["category"]
category = property(get_category)

def get_unique_args(self):
"""docstring for get_unique_args"""
if "unique_args" in self.sendgrid_headers.data:
# raise Exception(self.sendgrid_headers.data["unique_args"])
uniqueArgs = self.sendgrid_headers.data["unique_args"]
else:
uniqueArgs = None
return uniqueArgs
unique_args = property(get_unique_args)

def setup_connection(self):
"""docstring for setup_connection"""
# Set up the connection
connection = get_sendgrid_connection()
self.connection = connection
logger.debug("Connection: {c}".format(c=connection))

def prep_message_for_sending(self):
"""docstring for prep_message_for_sending"""
self.setup_connection()

# now = tz.localize(datetime.datetime.strptime(timestamp[:26], POSTMARK_DATETIME_STRING)).astimezone(pytz.utc)
uniqueArgs = {
"message_id": str(self._message_id),
# "submition_time": time.time(),
}
self._update_unique_args(uniqueArgs)

self.update_headers()


class SendGridEmailMessage(EmailMessage, SendGridEmailMessageMixin):
"""
Adapts Django's ``EmailMessage`` for use with SendGrid.
>>> from sendgrid.message import SendGridEmailMessage
>>> myEmail = "rbalfanz@gmail.com"
>>> mySendGridCategory = "django-sendgrid"
>>> e = SendGridEmailMessage("Subject", "Message", myEmail, [myEmail], headers={"Reply-To": myEmail})
>>> e.sendgrid_headers.setCategory(mySendGridCategory)
>>> response = e.send()
"""
sendgrid_headers = SmtpApiHeader()

def __init__(self, *args, **kwargs):
"""
Initialize the object.
"""
self._message_id = uuid.uuid4()
super(SendGridEmailMessage, self).__init__(*args, **kwargs)

def send(self, *args, **kwargs):
"""Sends the email message."""
self.prep_message_for_sending()

response = super(SendGridEmailMessage, self).send(*args, **kwargs)
logger.debug("Tried to send an email with SendGrid and got response {r}".format(r=response))
sendgrid_email_sent.send(sender=self, response=response)

return response


class SendGridEmailMultiAlternatives(EmailMultiAlternatives, SendGridEmailMessageMixin):
"""
Adapts Django's ``EmailMultiAlternatives`` for use with SendGrid.
"""
sendgrid_headers = SmtpApiHeader()

def __init__(self, *args, **kwargs):
self._message_id = uuid.uuid4()
super(SendGridEmailMultiAlternatives, self).__init__(*args, **kwargs)

def send(self, *args, **kwargs):
"""Sends the email message."""
self.prep_message_for_sending()

response = super(SendGridEmailMultiAlternatives, self).send(*args, **kwargs)
logger.debug("Tried to send an email with SendGrid and got response {r}".format(r=response))
sendgrid_email_sent.send(sender=self, response=response)

return response
39 changes: 39 additions & 0 deletions sendgrid/mixins.py
@@ -0,0 +1,39 @@
from django.conf import settings
from django.utils import simplejson

from utils import add_unsubscribes
from utils import delete_unsubscribes
from utils import get_unsubscribes


SENDGRID_EMAIL_USERNAME = getattr(settings, "SENDGRID_EMAIL_USERNAME", None)
SENDGRID_EMAIL_PASSWORD = getattr(settings, "SENDGRID_EMAIL_PASSWORD", None)


class SendGridUserMixin:
"""
Adds SendGrid related convienence functions and properties to ``User`` objects.
"""
def is_unsubscribed(self):
"""
Returns True if the ``User``.``email`` belongs to the unsubscribe list.
"""
response = get_unsubscribes(email=self.email)
results = simplejson.loads(response)
return len(results) > 0

def add_to_unsubscribes(self):
"""
Adds the ``User``.``email`` from the unsubscribe list.
"""
response = add_unsubscribes(email=self.email)
result = simplejson.loads(response)
return result

def delete_from_unsubscribes(self):
"""
Removes the ``User``.``email`` from the unsubscribe list.
"""
response = delete_unsubscribes(email=self.email)
result = simplejson.loads(response)
return result

0 comments on commit 5cd7c1d

Please sign in to comment.