Search code examples
pythonamazon-web-servicesamazon-cognitoamazon-cognito-triggers

How to send a custom message for CustomMessage_AdminCreateUser trigger?


When sending a custom email message for CustomMessage_AdminCreateUser trigger, I successfully change the emailSubject attribute in the event received from Amazon Cognito, but can't seem to change the emailMessage attribute.

The email sent from Cognito contains the correct customized subject, but the message is not customized at all, and it's always the one that is set in the Cognito pool settings.

The lambda handler which handles the event received from Cognito successfully customizes the message for these triggers:

  • CustomMessage_SignUp
  • CustomMessage_ResendCode
  • CustomMessage_ForgotPassword

But I can't seem to get it working (at least not completely) for CustomMessage_AdminCreateUser trigger.

I tried setting the email_verified user attribute to true to see if that attribute depends on successfully sending the customized mail to the created user. Also, I tried running the lambda in Docker container to see the output of the final event returned to the Cognito, but the event contains the correct data, both email subject and email message were customized.

def lambda_handler(event, context):
    if event['userPoolId'] == os.getenv('cognitoPoolId'):
        if CustomMessageTriggerEnum.has_value(event.get('triggerSource')):
            custom_message_trigger = CustomMessageTriggerEnum(event.get('triggerSource'))

            if custom_message_trigger == CustomMessageTriggerEnum.CustomMessageAdminCreateUser:
                custom_message_trigger = CustomMessageAdminCreateUser(event)
            else:
                return None

            custom_response = custom_message_trigger.get_custom_response(
                custom_message_trigger.ACTION,
                custom_message_trigger.EMAIL_SUBJECT,
                custom_message_trigger.EMAIL_MESSAGE
            )
            event = custom_message_trigger.set_custom_response(**custom_response)

            return event
class CustomMessageAdminCreateUser(BaseCustomMessageTrigger):
    """ Custom message admin create user trigger """

    ACTION = "changepassword"
    EMAIL_SUBJECT = "Welcome to {service}"
    EMAIL_MESSAGE = "Your account has been created. <a href='{0}'>Click here</a> to set your password and start using {service}."

    def __init__(self, event):
        super().__init__(event)
class BaseCustomMessageTrigger():
    """ Base custom message trigger """
    def __init__(self, event):
        self.event = event

    def get_custom_response(self, action, email_subject, email_message):
        """ Gets custom response params as dictionary """
        request = self.event.get('request')
        custom_response = {}
        url = self.get_url(
            action=action,
            code=request.get('codeParameter'),
            email=urlencode({'email': request['userAttributes'].get('email')})
        )
        custom_response['emailSubject'] = email_subject
        custom_response['emailMessage'] = email_message.format(url)

        return custom_response

    def set_custom_response(self, **kwargs):
        """ Updates the event response with provided kwargs """
        response = self.event.get('response')
        response.update(**kwargs)

        return self.event

    def get_url(self, action, code, email):
        """ Used for constructing URLs. """
        rawUrl = 'https://{0}/{1}?code={2}&{3}'
        return rawUrl.format(domain, action, code, email)

Solution

  • You have to avoid urlencode on response parameters because Lambda will add placeholders which will be replaced by Cognito later.