Browse files

Completely untested at this point, but this is the gist of what is ne…

…eded to get this running with celery. More to come tomorrow.
  • Loading branch information...
1 parent d1e80a3 commit 8b9321cfc01d0c04f7681063abeae337cfe21814 @gtaylor gtaylor committed Apr 13, 2011
Showing with 83 additions and 70 deletions.
  1. +10 −70 seacucumber/backend.py
  2. +73 −0 seacucumber/tasks.py
View
80 seacucumber/backend.py
@@ -1,84 +1,24 @@
from django.core.mail.backends.base import BaseEmailBackend
-from django.conf import settings
-import threading
-
-from boto.ses import SESConnection
+from seacucumber.tasks import SendEmailTask
class SESBackend(BaseEmailBackend):
"""
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):
- """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.
"""
- if not email_messages:
- return
-
- new_conn_created = self.open()
- if not self.connection:
- # Failed silently
- return
-
num_sent = 0
for message in email_messages:
- try:
- response = self.connection.send_raw_email(
- source=message.from_email,
- destinations=message.recipients(),
- raw_message=message.message().as_string(),
- )
- send_response = response['SendRawEmailResponse']
- 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()
-
+ # Hand this off to a celery task.
+ SendEmailTask.delay(
+ message.from_email,
+ message.recipients(),
+ message.message().as_string(),
+ )
+ num_sent += 1
return num_sent
View
73 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.