Skip to content

Commit

Permalink
Completely untested at this point, but this is the gist of what is ne…
Browse files Browse the repository at this point in the history
…eded to get this running with celery. More to come tomorrow.
  • Loading branch information
Greg Taylor committed Apr 13, 2011
1 parent d1e80a3 commit 8b9321c
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 70 deletions.
80 changes: 10 additions & 70 deletions seacucumber/backend.py
@@ -1,84 +1,24 @@
from django.core.mail.backends.base import BaseEmailBackend from django.core.mail.backends.base import BaseEmailBackend
from django.conf import settings


import threading from seacucumber.tasks import SendEmailTask

from boto.ses import SESConnection


class SESBackend(BaseEmailBackend): class SESBackend(BaseEmailBackend):
""" """
A Django Email backend that uses Amazon's Simple Email Service. A Django Email backend that uses Amazon's Simple Email Service.
""" """
def __init__(self, fail_silently=False, *args, **kwargs):
super(SESBackend, self).__init__(fail_silently=fail_silently, *args,
**kwargs)

self._access_key_id = getattr(settings, 'AWS_ACCESS_KEY_ID', None)
self._access_key = getattr(settings, 'AWS_SECRET_ACCESS_KEY', None)
self._api_endpoint = getattr(settings, 'AWS_SES_API_HOST',
SESConnection.DefaultHost)

self.connection = None

def open(self):
"""Create a connection to the AWS API server. This can be reused for
sending multiple emails.
"""
if self.connection:
return False

try:
self.connection = SESConnection(
aws_access_key_id=self._access_key_id,
aws_secret_access_key=self._access_key,
host=self._api_endpoint,
)
except:
if not self.fail_silently:
raise

def close(self):
"""Close any open HTTP connections to the API server.
"""
try:
self.connection.close()
self.connection = None
except:
if not self.fail_silently:
raise

def send_messages(self, email_messages): def send_messages(self, email_messages):
"""Sends one or more EmailMessage objects and returns the number of """
Sends one or more EmailMessage objects and returns the number of
email messages sent. email messages sent.
""" """
if not email_messages:
return

new_conn_created = self.open()
if not self.connection:
# Failed silently
return

num_sent = 0 num_sent = 0
for message in email_messages: for message in email_messages:
try: # Hand this off to a celery task.
response = self.connection.send_raw_email( SendEmailTask.delay(
source=message.from_email, message.from_email,
destinations=message.recipients(), message.recipients(),
raw_message=message.message().as_string(), message.message().as_string(),
) )
send_response = response['SendRawEmailResponse'] num_sent += 1
send_result = send_response['SendRawEmailResult']
message.extra_headers['Message-Id'] = send_result['MessageId']

num_sent += 1
except SESConnection.ResponseError:
if not self.fail_silently:
raise
pass

if new_conn_created:
self.close()

return num_sent return num_sent


73 changes: 73 additions & 0 deletions seacucumber/tasks.py
@@ -0,0 +1,73 @@
from django.conf import settings
from boto.ses import SESConnection
from celery.task import Task

class SendEmailTask(Task):
"""
Sends an email through Boto's SES API module.
"""
# TODO: Make this a setting.
max_retries = 60
# TODO: Make this a setting.
default_retry_delay = 60

def __init__(self, *args, **kwargs):
super(SendEmailTask, self).__init__(*args, **kwargs)

self.connection = None
self._access_key_id = getattr(settings, 'AWS_ACCESS_KEY_ID', None)
self._access_key = getattr(settings, 'AWS_SECRET_ACCESS_KEY', None)
self._api_endpoint = getattr(settings, 'AWS_SES_API_HOST',
SESConnection.DefaultHost)

def run(self, from_email, recipients, message):
"""
This does the dirty work.
TOOD: Document params.
"""
self._open_ses_conn()
try:
self.connection.send_raw_email(
source=from_email,
destinations=recipients,
raw_message=message,
)
except SESConnection.ResponseError:
self.retry(
countdown=self.default_retry_delay,
exc=SESConnection.ResponseError,
)
self._close_ses_conn()


def _open_ses_conn(self):
"""
Create a connection to the AWS API server. This can be reused for
sending multiple emails.
"""
if self.connection:
return

try:
self.connection = SESConnection(
aws_access_key_id=self._access_key_id,
aws_secret_access_key=self._access_key,
host=self._api_endpoint,
)
# TODO: Get more specific with this exception block.
except:
self.retry(
countdown=self.default_retry_delay,
)

def _close_ses_conn(self):
"""
Close any open HTTP connections to the API server.
"""
try:
self.connection.close()
self.connection = None
except:
# It doesn't really matter at this point.
pass

0 comments on commit 8b9321c

Please sign in to comment.