Implementing send_templated_email

This commit is contained in:
Kyle Jones 2019-10-02 08:39:35 +01:00
parent 4497f18c1a
commit 1d5140e11d
3 changed files with 109 additions and 3 deletions

View File

@ -49,6 +49,21 @@ class Message(BaseModel):
self.destinations = destinations self.destinations = destinations
class TemplateMessage(BaseModel):
def __init__(self,
message_id,
source,
template,
template_data,
destinations):
self.id = message_id
self.source = source
self.template = template
self.template_data = template_data
self.destinations = destinations
class RawMessage(BaseModel): class RawMessage(BaseModel):
def __init__(self, message_id, source, destinations, raw_data): def __init__(self, message_id, source, destinations, raw_data):
@ -123,10 +138,34 @@ class SESBackend(BaseBackend):
self.sent_message_count += recipient_count self.sent_message_count += recipient_count
return message return message
def send_templated_email(self, source, template, template_data, destinations, region):
recipient_count = sum(map(len, destinations.values()))
if recipient_count > RECIPIENT_LIMIT:
raise MessageRejectedError('Too many recipients.')
if not self._is_verified_address(source):
raise MessageRejectedError(
"Email address not verified %s" % source
)
self.__process_sns_feedback__(source, destinations, region)
message_id = get_random_message_id()
message = TemplateMessage(message_id,
source,
template,
template_data,
destinations)
self.sent_messages.append(message)
self.sent_message_count += recipient_count
return message
def __type_of_message__(self, destinations): def __type_of_message__(self, destinations):
"""Checks the destination for any special address that could indicate delivery, complaint or bounce """Checks the destination for any special address that could indicate delivery,
like in SES simualtor""" complaint or bounce like in SES simualtor"""
alladdress = destinations.get("ToAddresses", []) + destinations.get("CcAddresses", []) + destinations.get("BccAddresses", []) alladdress = destinations.get(
"ToAddresses", []) + destinations.get(
"CcAddresses", []) + destinations.get(
"BccAddresses", [])
for addr in alladdress: for addr in alladdress:
if SESFeedback.SUCCESS_ADDR in addr: if SESFeedback.SUCCESS_ADDR in addr:
return SESFeedback.DELIVERY return SESFeedback.DELIVERY

View File

@ -74,6 +74,33 @@ class EmailResponse(BaseResponse):
template = self.response_template(SEND_EMAIL_RESPONSE) template = self.response_template(SEND_EMAIL_RESPONSE)
return template.render(message=message) return template.render(message=message)
def send_templated_email(self):
source = self.querystring.get('Source')[0]
template = self.querystring.get('Template')
template_data = self.querystring.get('TemplateData')
destinations = {
'ToAddresses': [],
'CcAddresses': [],
'BccAddresses': [],
}
for dest_type in destinations:
# consume up to 51 to allow exception
for i in six.moves.range(1, 52):
field = 'Destination.%s.member.%s' % (dest_type, i)
address = self.querystring.get(field)
if address is None:
break
destinations[dest_type].append(address[0])
message = ses_backend.send_templated_email(source,
template,
template_data,
destinations,
self.region)
template = self.response_template(SEND_TEMPLATED_EMAIL_RESPONSE)
return template.render(message=message)
def send_raw_email(self): def send_raw_email(self):
source = self.querystring.get('Source') source = self.querystring.get('Source')
if source is not None: if source is not None:
@ -193,6 +220,15 @@ SEND_EMAIL_RESPONSE = """<SendEmailResponse xmlns="http://ses.amazonaws.com/doc/
</ResponseMetadata> </ResponseMetadata>
</SendEmailResponse>""" </SendEmailResponse>"""
SEND_TEMPLATED_EMAIL_RESPONSE = """<SendTemplatedEmailResponse xmlns="http://ses.amazonaws.com/doc/2010-12-01/">
<SendTemplatedEmailResult>
<MessageId>{{ message.id }}</MessageId>
</SendTemplatedEmailResult>
<ResponseMetadata>
<RequestId>d5964849-c866-11e0-9beb-01a62d68c57f</RequestId>
</ResponseMetadata>
</SendTemplatedEmailResponse>"""
SEND_RAW_EMAIL_RESPONSE = """<SendRawEmailResponse xmlns="http://ses.amazonaws.com/doc/2010-12-01/"> SEND_RAW_EMAIL_RESPONSE = """<SendRawEmailResponse xmlns="http://ses.amazonaws.com/doc/2010-12-01/">
<SendRawEmailResult> <SendRawEmailResult>
<MessageId>{{ message.id }}</MessageId> <MessageId>{{ message.id }}</MessageId>

View File

@ -80,6 +80,37 @@ def test_send_email():
sent_count.should.equal(3) sent_count.should.equal(3)
@mock_ses
def test_send_templated_email():
conn = boto3.client('ses', region_name='us-east-1')
kwargs = dict(
Source="test@example.com",
Destination={
"ToAddresses": ["test_to@example.com"],
"CcAddresses": ["test_cc@example.com"],
"BccAddresses": ["test_bcc@example.com"],
},
Template="test_template",
TemplateData='{\"name\": \"test\"}'
)
conn.send_templated_email.when.called_with(
**kwargs).should.throw(ClientError)
conn.verify_domain_identity(Domain='example.com')
conn.send_templated_email(**kwargs)
too_many_addresses = list('to%s@example.com' % i for i in range(51))
conn.send_templated_email.when.called_with(
**dict(kwargs, Destination={'ToAddresses': too_many_addresses})
).should.throw(ClientError)
send_quota = conn.get_send_quota()
sent_count = int(send_quota['SentLast24Hours'])
sent_count.should.equal(3)
@mock_ses @mock_ses
def test_send_html_email(): def test_send_html_email():
conn = boto3.client('ses', region_name='us-east-1') conn = boto3.client('ses', region_name='us-east-1')