# (c) 2021 Amazon Web Services, Inc. or its affiliates. All Rights Reserved. # This AWS Content is provided subject to the terms of the AWS Customer Agreement available at # https://aws.amazon.com/agreement/ or other written agreement between Customer # and Amazon Web Services, Inc. """Notifier. Provies core logic for the Notifier Lambda Function. """ import logging import boto3 from botocore.exceptions import ClientError from config import Config import smtplib from email.mime.text import MIMEText from email.mime.multipart import MIMEMultipart log = logging.getLogger(__name__) log.setLevel(logging.INFO) class Notifier: def __init__(self, sender_email: str, recipient_email: str, template_s3_bucket: str, template_s3_prefix: str, email_template: str, subject: str) -> None: self.sender_email = sender_email self.recipient_email = recipient_email self.template_s3_bucket = template_s3_bucket self.template_s3_prefix = template_s3_prefix self.email_template = email_template self.subject = subject @staticmethod def __parse_arn(arn): # http://docs.aws.amazon.com/general/latest/gr/aws-arns-and-namespaces.html elements = arn.split(':', 5) result = { 'arn': elements[0], 'partition': elements[1], 'service': elements[2], 'region': elements[3], 'account': elements[4], 'resource': elements[5], 'resource_type': None } if '/' in result['resource']: result['resource_type'], result['resource'] = \ result['resource'].split('/', 1) # NOQA elif ':' in result['resource']: result['resource_type'], result['resource'] = \ result['resource'].split(':', 1) # NOQA return result def __get_template(self, template_name): log.info(f'Getting template {template_name} from S3') s3 = boto3.client('s3') try: obj = s3.get_object( Bucket=self.template_s3_bucket, Key=f'{self.template_s3_prefix}/Template/{template_name}' ) data = obj['Body'].read() template = data.decode('utf-8') log.info(f'Successfully retrieved content for {template_name}') return template except ClientError as err: log.error( f'Error while getting file contents for {template_name}' f' - {err}' ) def __render_email_body(self, template_values: dict): subject = self.subject # get the appropriate S3 Key for the template template_s3_key = self.email_template if not template_s3_key: log.error(f'Unable to get template for {subject}') raise ValueError(f'Unable to get template for {subject}') else: # stream the template contents from S3 email = self.__get_template(template_s3_key) log.info('Rendering email contents') for k, v in template_values.items(): placeholder = '{{' + f'{k}' + '}}' if isinstance(v, list): value = self.__format_html_list(v) else: value = str(v) email = email.replace(placeholder, value) log.info(f'Rendered Email: {email}') return email @staticmethod def __format_html_list(value): value_formatted = '' for line in value: value_formatted += f'• {str(line)}<br>' return value_formatted def send_email(self, template_values): if Config.runLambdaInVPC: self.send_smtp_email(template_values) else: self.send_ses_email(template_values) def send_ses_email(self, template_values): my_session = boto3.session.Session() my_region = my_session.region_name ses = my_session.client('ses', region_name=my_region) email_body = self.__render_email_body(template_values) try: log.info(f'Sending email to {self.recipient_email}') resp = ses.send_email( Source=self.sender_email, Destination={ 'ToAddresses': [ self.recipient_email, ] }, Message={ 'Subject': { 'Data': self.subject }, 'Body': { 'Text': { 'Data': email_body }, 'Html': { 'Data': email_body } } } ) log.info('Email sent successfully - Exiting Gracefully') return resp except ClientError as err: log.error( f'Encountered error while attempting to send email - {err}' ) print(err) raise err def send_smtp_email(self, template_values): my_session = boto3.session.Session() my_region = my_session.region_name port = 465 email_body = self.__render_email_body(template_values) message = MIMEMultipart() message['Subject'] = self.subject message['From'] = self.sender_email message['To'] = self.recipient_email message.attach(MIMEText(email_body, "html")) msgbody = message.as_string() ssm = my_session.client('ssm', region_name=my_region, endpoint_url="https://ssm." + my_region + ".amazonaws.com") user = ssm.get_parameter(Name=Config.smtp_user_param, WithDecryption=False) password = ssm.get_parameter(Name=Config.smtp_password_param, WithDecryption=True) try: log.info(f'Sending email to {self.recipient_email}') server = smtplib.SMTP_SSL("email-smtp." + my_region + ".amazonaws.com", port) server.login(user.get("Parameter").get("Value"), password.get("Parameter").get("Value")) server.sendmail(self.sender_email, self.recipient_email, msgbody) log.info('Email sent successfully - Exiting Gracefully') except ClientError as err: log.error( f'Encountered error while attempting to send email - {err}' ) print(err) raise err