Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
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...
commit 8b9321cfc01d0c04f7681063abeae337cfe21814 1 parent d1e80a3
Greg Taylor gtaylor authored
Showing with 83 additions and 70 deletions.
  1. +10 −70 seacucumber/backend.py
  2. +73 −0 seacucumber/tasks.py
80 seacucumber/backend.py
View
@@ -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
73 seacucumber/tasks.py
View
@@ -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
Please sign in to comment.
Something went wrong with that request. Please try again.