import boto3 from flask import current_app from monotonic import monotonic from app.clients import STATISTICS_DELIVERED, STATISTICS_FAILURE from app.clients.email import (EmailClientException, EmailClient) ses_response_map = { 'Bounce': { "message": 'Bounced', "success": False, "notification_status": 'failed', "notification_statistics_status": STATISTICS_FAILURE }, 'Delivery': { "message": 'Delivered', "success": True, "notification_status": 'delivered', "notification_statistics_status": STATISTICS_DELIVERED }, 'Complaint': { "message": 'Complaint', "success": True, "notification_status": 'delivered', "notification_statistics_status": STATISTICS_DELIVERED } } def get_aws_responses(status): return ses_response_map[status] class AwsSesClientException(EmailClientException): pass class AwsSesClient(EmailClient): ''' Amazon SES email client. ''' def init_app(self, region, statsd_client, *args, **kwargs): self._client = boto3.client('ses', region_name=region) super(AwsSesClient, self).__init__(*args, **kwargs) self.name = 'ses' self.statsd_client = statsd_client def get_name(self): return self.name def send_email(self, source, to_addresses, subject, body, html_body='', reply_to_addresses=None): try: if isinstance(to_addresses, str): to_addresses = [to_addresses] if reply_to_addresses and isinstance(reply_to_addresses, str): reply_to_addresses = [reply_to_addresses] elif reply_to_addresses is None: reply_to_addresses = [] body = { 'Text': {'Data': body} } if html_body: body.update({ 'Html': {'Data': html_body} }) start_time = monotonic() response = self._client.send_email( Source=source, Destination={ 'ToAddresses': to_addresses, 'CcAddresses': [], 'BccAddresses': [] }, Message={ 'Subject': { 'Data': subject, }, 'Body': body }, ReplyToAddresses=reply_to_addresses) elapsed_time = monotonic() - start_time current_app.logger.info("AWS SES request finished in {}".format(elapsed_time)) self.statsd_client.timing("notifications.clients.ses.request-time", elapsed_time) return response['MessageId'] except Exception as e: # TODO logging exceptions self.statsd_client.incr("notifications.clients.ses.error") raise AwsSesClientException(str(e))