Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

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 2 changed files with 83 additions and 70 deletions. Show diff stats Hide diff stats

  1. +10 70 seacucumber/backend.py
  2. +73 0 seacucumber/tasks.py
80 seacucumber/backend.py
... ... @@ -1,84 +1,24 @@
1 1 from django.core.mail.backends.base import BaseEmailBackend
2   -from django.conf import settings
3 2
4   -import threading
5   -
6   -from boto.ses import SESConnection
  3 +from seacucumber.tasks import SendEmailTask
7 4
8 5 class SESBackend(BaseEmailBackend):
9 6 """
10 7 A Django Email backend that uses Amazon's Simple Email Service.
11 8 """
12   - def __init__(self, fail_silently=False, *args, **kwargs):
13   - super(SESBackend, self).__init__(fail_silently=fail_silently, *args,
14   - **kwargs)
15   -
16   - self._access_key_id = getattr(settings, 'AWS_ACCESS_KEY_ID', None)
17   - self._access_key = getattr(settings, 'AWS_SECRET_ACCESS_KEY', None)
18   - self._api_endpoint = getattr(settings, 'AWS_SES_API_HOST',
19   - SESConnection.DefaultHost)
20   -
21   - self.connection = None
22   -
23   - def open(self):
24   - """Create a connection to the AWS API server. This can be reused for
25   - sending multiple emails.
26   - """
27   - if self.connection:
28   - return False
29   -
30   - try:
31   - self.connection = SESConnection(
32   - aws_access_key_id=self._access_key_id,
33   - aws_secret_access_key=self._access_key,
34   - host=self._api_endpoint,
35   - )
36   - except:
37   - if not self.fail_silently:
38   - raise
39   -
40   - def close(self):
41   - """Close any open HTTP connections to the API server.
42   - """
43   - try:
44   - self.connection.close()
45   - self.connection = None
46   - except:
47   - if not self.fail_silently:
48   - raise
49   -
50 9 def send_messages(self, email_messages):
51   - """Sends one or more EmailMessage objects and returns the number of
  10 + """
  11 + Sends one or more EmailMessage objects and returns the number of
52 12 email messages sent.
53 13 """
54   - if not email_messages:
55   - return
56   -
57   - new_conn_created = self.open()
58   - if not self.connection:
59   - # Failed silently
60   - return
61   -
62 14 num_sent = 0
63 15 for message in email_messages:
64   - try:
65   - response = self.connection.send_raw_email(
66   - source=message.from_email,
67   - destinations=message.recipients(),
68   - raw_message=message.message().as_string(),
69   - )
70   - send_response = response['SendRawEmailResponse']
71   - send_result = send_response['SendRawEmailResult']
72   - message.extra_headers['Message-Id'] = send_result['MessageId']
73   -
74   - num_sent += 1
75   - except SESConnection.ResponseError:
76   - if not self.fail_silently:
77   - raise
78   - pass
79   -
80   - if new_conn_created:
81   - self.close()
82   -
  16 + # Hand this off to a celery task.
  17 + SendEmailTask.delay(
  18 + message.from_email,
  19 + message.recipients(),
  20 + message.message().as_string(),
  21 + )
  22 + num_sent += 1
83 23 return num_sent
84 24
73 seacucumber/tasks.py
... ... @@ -0,0 +1,73 @@
  1 +from django.conf import settings
  2 +from boto.ses import SESConnection
  3 +from celery.task import Task
  4 +
  5 +class SendEmailTask(Task):
  6 + """
  7 + Sends an email through Boto's SES API module.
  8 + """
  9 + # TODO: Make this a setting.
  10 + max_retries = 60
  11 + # TODO: Make this a setting.
  12 + default_retry_delay = 60
  13 +
  14 + def __init__(self, *args, **kwargs):
  15 + super(SendEmailTask, self).__init__(*args, **kwargs)
  16 +
  17 + self.connection = None
  18 + self._access_key_id = getattr(settings, 'AWS_ACCESS_KEY_ID', None)
  19 + self._access_key = getattr(settings, 'AWS_SECRET_ACCESS_KEY', None)
  20 + self._api_endpoint = getattr(settings, 'AWS_SES_API_HOST',
  21 + SESConnection.DefaultHost)
  22 +
  23 + def run(self, from_email, recipients, message):
  24 + """
  25 + This does the dirty work.
  26 +
  27 + TOOD: Document params.
  28 + """
  29 + self._open_ses_conn()
  30 + try:
  31 + self.connection.send_raw_email(
  32 + source=from_email,
  33 + destinations=recipients,
  34 + raw_message=message,
  35 + )
  36 + except SESConnection.ResponseError:
  37 + self.retry(
  38 + countdown=self.default_retry_delay,
  39 + exc=SESConnection.ResponseError,
  40 + )
  41 + self._close_ses_conn()
  42 +
  43 +
  44 + def _open_ses_conn(self):
  45 + """
  46 + Create a connection to the AWS API server. This can be reused for
  47 + sending multiple emails.
  48 + """
  49 + if self.connection:
  50 + return
  51 +
  52 + try:
  53 + self.connection = SESConnection(
  54 + aws_access_key_id=self._access_key_id,
  55 + aws_secret_access_key=self._access_key,
  56 + host=self._api_endpoint,
  57 + )
  58 + # TODO: Get more specific with this exception block.
  59 + except:
  60 + self.retry(
  61 + countdown=self.default_retry_delay,
  62 + )
  63 +
  64 + def _close_ses_conn(self):
  65 + """
  66 + Close any open HTTP connections to the API server.
  67 + """
  68 + try:
  69 + self.connection.close()
  70 + self.connection = None
  71 + except:
  72 + # It doesn't really matter at this point.
  73 + pass

0 comments on commit 8b9321c

Please sign in to comment.
Something went wrong with that request. Please try again.