Merge pull request #2946 from usmangani1/LSTACKISSUE909
SES Enhancement Adding get_send_statistics,create_configuration_set functions.
This commit is contained in:
commit
2c9409faaa
@ -7,3 +7,21 @@ class MessageRejectedError(RESTError):
|
||||
|
||||
def __init__(self, message):
|
||||
super(MessageRejectedError, self).__init__("MessageRejected", message)
|
||||
|
||||
|
||||
class ConfigurationSetDoesNotExist(RESTError):
|
||||
code = 400
|
||||
|
||||
def __init__(self, message):
|
||||
super(ConfigurationSetDoesNotExist, self).__init__(
|
||||
"ConfigurationSetDoesNotExist", message
|
||||
)
|
||||
|
||||
|
||||
class EventDestinationAlreadyExists(RESTError):
|
||||
code = 400
|
||||
|
||||
def __init__(self, message):
|
||||
super(EventDestinationAlreadyExists, self).__init__(
|
||||
"EventDestinationAlreadyExists", message
|
||||
)
|
||||
|
@ -1,11 +1,16 @@
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import datetime
|
||||
import email
|
||||
from email.utils import parseaddr
|
||||
|
||||
from moto.core import BaseBackend, BaseModel
|
||||
from moto.sns.models import sns_backends
|
||||
from .exceptions import MessageRejectedError
|
||||
from .exceptions import (
|
||||
MessageRejectedError,
|
||||
ConfigurationSetDoesNotExist,
|
||||
EventDestinationAlreadyExists,
|
||||
)
|
||||
from .utils import get_random_message_id
|
||||
from .feedback import COMMON_MAIL, BOUNCE, COMPLAINT, DELIVERY
|
||||
|
||||
@ -81,7 +86,11 @@ class SESBackend(BaseBackend):
|
||||
self.domains = []
|
||||
self.sent_messages = []
|
||||
self.sent_message_count = 0
|
||||
self.rejected_messages_count = 0
|
||||
self.sns_topics = {}
|
||||
self.config_set = {}
|
||||
self.config_set_event_destination = {}
|
||||
self.event_destinations = {}
|
||||
|
||||
def _is_verified_address(self, source):
|
||||
_, address = parseaddr(source)
|
||||
@ -118,6 +127,7 @@ class SESBackend(BaseBackend):
|
||||
if recipient_count > RECIPIENT_LIMIT:
|
||||
raise MessageRejectedError("Too many recipients.")
|
||||
if not self._is_verified_address(source):
|
||||
self.rejected_messages_count += 1
|
||||
raise MessageRejectedError("Email address not verified %s" % source)
|
||||
|
||||
self.__process_sns_feedback__(source, destinations, region)
|
||||
@ -135,6 +145,7 @@ class SESBackend(BaseBackend):
|
||||
if recipient_count > RECIPIENT_LIMIT:
|
||||
raise MessageRejectedError("Too many recipients.")
|
||||
if not self._is_verified_address(source):
|
||||
self.rejected_messages_count += 1
|
||||
raise MessageRejectedError("Email address not verified %s" % source)
|
||||
|
||||
self.__process_sns_feedback__(source, destinations, region)
|
||||
@ -237,5 +248,34 @@ class SESBackend(BaseBackend):
|
||||
|
||||
return {}
|
||||
|
||||
def create_configuration_set(self, configuration_set_name):
|
||||
self.config_set[configuration_set_name] = 1
|
||||
return {}
|
||||
|
||||
def create_configuration_set_event_destination(
|
||||
self, configuration_set_name, event_destination
|
||||
):
|
||||
|
||||
if self.config_set.get(configuration_set_name) is None:
|
||||
raise ConfigurationSetDoesNotExist("Invalid Configuration Set Name.")
|
||||
|
||||
if self.event_destinations.get(event_destination["Name"]):
|
||||
raise EventDestinationAlreadyExists("Duplicate Event destination Name.")
|
||||
|
||||
self.config_set_event_destination[configuration_set_name] = event_destination
|
||||
self.event_destinations[event_destination["Name"]] = 1
|
||||
|
||||
return {}
|
||||
|
||||
def get_send_statistics(self):
|
||||
|
||||
statistics = {}
|
||||
statistics["DeliveryAttempts"] = self.sent_message_count
|
||||
statistics["Rejects"] = self.rejected_messages_count
|
||||
statistics["Complaints"] = 0
|
||||
statistics["Bounces"] = 0
|
||||
statistics["Timestamp"] = datetime.datetime.utcnow()
|
||||
return statistics
|
||||
|
||||
|
||||
ses_backend = SESBackend()
|
||||
|
@ -133,6 +133,48 @@ class EmailResponse(BaseResponse):
|
||||
template = self.response_template(SET_IDENTITY_NOTIFICATION_TOPIC_RESPONSE)
|
||||
return template.render()
|
||||
|
||||
def get_send_statistics(self):
|
||||
statistics = ses_backend.get_send_statistics()
|
||||
template = self.response_template(GET_SEND_STATISTICS)
|
||||
return template.render(all_statistics=[statistics])
|
||||
|
||||
def create_configuration_set(self):
|
||||
configuration_set_name = self.querystring.get("ConfigurationSet.Name")[0]
|
||||
ses_backend.create_configuration_set(
|
||||
configuration_set_name=configuration_set_name
|
||||
)
|
||||
template = self.response_template(CREATE_CONFIGURATION_SET)
|
||||
return template.render()
|
||||
|
||||
def create_configuration_set_event_destination(self):
|
||||
|
||||
configuration_set_name = self._get_param("ConfigurationSetName")
|
||||
is_configuration_event_enabled = self.querystring.get(
|
||||
"EventDestination.Enabled"
|
||||
)[0]
|
||||
configuration_event_name = self.querystring.get("EventDestination.Name")[0]
|
||||
event_topic_arn = self.querystring.get(
|
||||
"EventDestination.SNSDestination.TopicARN"
|
||||
)[0]
|
||||
event_matching_types = self._get_multi_param(
|
||||
"EventDestination.MatchingEventTypes.member"
|
||||
)
|
||||
|
||||
event_destination = {
|
||||
"Name": configuration_event_name,
|
||||
"Enabled": is_configuration_event_enabled,
|
||||
"EventMatchingTypes": event_matching_types,
|
||||
"SNSDestination": event_topic_arn,
|
||||
}
|
||||
|
||||
ses_backend.create_configuration_set_event_destination(
|
||||
configuration_set_name=configuration_set_name,
|
||||
event_destination=event_destination,
|
||||
)
|
||||
|
||||
template = self.response_template(CREATE_CONFIGURATION_SET_EVENT_DESTINATION)
|
||||
return template.render()
|
||||
|
||||
|
||||
VERIFY_EMAIL_IDENTITY = """<VerifyEmailIdentityResponse xmlns="http://ses.amazonaws.com/doc/2010-12-01/">
|
||||
<VerifyEmailIdentityResult/>
|
||||
@ -248,3 +290,35 @@ SET_IDENTITY_NOTIFICATION_TOPIC_RESPONSE = """<SetIdentityNotificationTopicRespo
|
||||
<RequestId>47e0ef1a-9bf2-11e1-9279-0100e8cf109a</RequestId>
|
||||
</ResponseMetadata>
|
||||
</SetIdentityNotificationTopicResponse>"""
|
||||
|
||||
GET_SEND_STATISTICS = """<GetSendStatisticsResponse xmlns="http://ses.amazonaws.com/doc/2010-12-01/">
|
||||
<SendDataPoints>
|
||||
{% for statistics in all_statistics %}
|
||||
<item>
|
||||
<DeliveryAttempts>{{ statistics["DeliveryAttempts"] }}</DeliveryAttempts>
|
||||
<Rejects>{{ statistics["Rejects"] }}</Rejects>
|
||||
<Bounces>{{ statistics["Bounces"] }}</Bounces>
|
||||
<Complaints>{{ statistics["Complaints"] }}</Complaints>
|
||||
<Timestamp>{{ statistics["Timestamp"] }}</Timestamp>
|
||||
</item>
|
||||
{% endfor %}
|
||||
</SendDataPoints>
|
||||
<ResponseMetadata>
|
||||
<RequestId>e0abcdfa-c866-11e0-b6d0-273d09173z49</RequestId>
|
||||
</ResponseMetadata>
|
||||
</GetSendStatisticsResponse>"""
|
||||
|
||||
CREATE_CONFIGURATION_SET = """<CreateConfigurationSetResponse xmlns="http://ses.amazonaws.com/doc/2010-12-01/">
|
||||
<CreateConfigurationSetResult/>
|
||||
<ResponseMetadata>
|
||||
<RequestId>47e0ef1a-9bf2-11e1-9279-0100e8cf109a</RequestId>
|
||||
</ResponseMetadata>
|
||||
</CreateConfigurationSetResponse>"""
|
||||
|
||||
|
||||
CREATE_CONFIGURATION_SET_EVENT_DESTINATION = """<CreateConfigurationSetEventDestinationResponse xmlns="http://ses.amazonaws.com/doc/2010-12-01/">
|
||||
<CreateConfigurationSetEventDestinationResult/>
|
||||
<ResponseMetadata>
|
||||
<RequestId>67e0ef1a-9bf2-11e1-9279-0100e8cf109a</RequestId>
|
||||
</ResponseMetadata>
|
||||
</CreateConfigurationSetEventDestinationResponse>"""
|
||||
|
@ -127,3 +127,45 @@ def test_send_raw_email():
|
||||
send_quota["GetSendQuotaResponse"]["GetSendQuotaResult"]["SentLast24Hours"]
|
||||
)
|
||||
sent_count.should.equal(1)
|
||||
|
||||
|
||||
@mock_ses_deprecated
|
||||
def test_get_send_statistics():
|
||||
conn = boto.connect_ses("the_key", "the_secret")
|
||||
|
||||
conn.send_email.when.called_with(
|
||||
"test@example.com",
|
||||
"test subject",
|
||||
"<span>test body</span>",
|
||||
"test_to@example.com",
|
||||
format="html",
|
||||
).should.throw(BotoServerError)
|
||||
|
||||
# tests to verify rejects in get_send_statistics
|
||||
result = conn.get_send_statistics()
|
||||
|
||||
reject_count = int(
|
||||
result["GetSendStatisticsResponse"]["SendDataPoints"][0]["Rejects"]
|
||||
)
|
||||
delivery_count = int(
|
||||
result["GetSendStatisticsResponse"]["SendDataPoints"][0]["DeliveryAttempts"]
|
||||
)
|
||||
reject_count.should.equal(1)
|
||||
delivery_count.should.equal(0)
|
||||
|
||||
conn.verify_email_identity("test@example.com")
|
||||
conn.send_email(
|
||||
"test@example.com", "test subject", "test body", "test_to@example.com"
|
||||
)
|
||||
|
||||
# tests to delivery attempts in get_send_statistics
|
||||
result = conn.get_send_statistics()
|
||||
|
||||
reject_count = int(
|
||||
result["GetSendStatisticsResponse"]["SendDataPoints"][0]["Rejects"]
|
||||
)
|
||||
delivery_count = int(
|
||||
result["GetSendStatisticsResponse"]["SendDataPoints"][0]["DeliveryAttempts"]
|
||||
)
|
||||
reject_count.should.equal(1)
|
||||
delivery_count.should.equal(1)
|
||||
|
@ -4,6 +4,8 @@ import boto3
|
||||
from botocore.exceptions import ClientError
|
||||
from six.moves.email_mime_multipart import MIMEMultipart
|
||||
from six.moves.email_mime_text import MIMEText
|
||||
from nose.tools import assert_raises
|
||||
|
||||
|
||||
import sure # noqa
|
||||
|
||||
@ -227,3 +229,51 @@ def test_send_email_notification_with_encoded_sender():
|
||||
Message={"Subject": {"Data": "hi",}, "Body": {"Text": {"Data": "there",}}},
|
||||
)
|
||||
response["ResponseMetadata"]["HTTPStatusCode"].should.equal(200)
|
||||
|
||||
|
||||
@mock_ses
|
||||
def test_create_configuration_set():
|
||||
conn = boto3.client("ses", region_name="us-east-1")
|
||||
conn.create_configuration_set(ConfigurationSet=dict({"Name": "test"}))
|
||||
|
||||
conn.create_configuration_set_event_destination(
|
||||
ConfigurationSetName="test",
|
||||
EventDestination={
|
||||
"Name": "snsEvent",
|
||||
"Enabled": True,
|
||||
"MatchingEventTypes": ["send",],
|
||||
"SNSDestination": {
|
||||
"TopicARN": "arn:aws:sns:us-east-1:123456789012:myTopic"
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
with assert_raises(ClientError) as ex:
|
||||
conn.create_configuration_set_event_destination(
|
||||
ConfigurationSetName="failtest",
|
||||
EventDestination={
|
||||
"Name": "snsEvent",
|
||||
"Enabled": True,
|
||||
"MatchingEventTypes": ["send",],
|
||||
"SNSDestination": {
|
||||
"TopicARN": "arn:aws:sns:us-east-1:123456789012:myTopic"
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
ex.exception.response["Error"]["Code"].should.equal("ConfigurationSetDoesNotExist")
|
||||
|
||||
with assert_raises(ClientError) as ex:
|
||||
conn.create_configuration_set_event_destination(
|
||||
ConfigurationSetName="test",
|
||||
EventDestination={
|
||||
"Name": "snsEvent",
|
||||
"Enabled": True,
|
||||
"MatchingEventTypes": ["send",],
|
||||
"SNSDestination": {
|
||||
"TopicARN": "arn:aws:sns:us-east-1:123456789012:myTopic"
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
ex.exception.response["Error"]["Code"].should.equal("EventDestinationAlreadyExists")
|
||||
|
Loading…
Reference in New Issue
Block a user