

End of support notice: On May 20, 2026, AWS will end support for AWS IoT Events. After May 20, 2026, you will no longer be able to access the AWS IoT Events console or AWS IoT Events resources. For more information, see [AWS IoT Events end of support](https://docs.aws.amazon.com/iotevents/latest/developerguide/iotevents-end-of-support.html).

# Managing alarm notifications in AWS IoT Events
<a name="lambda-support"></a>

AWS IoT Events integrates with Lambda, offering custom event processing capabilities. This section explores how to use Lambda functions within your AWS IoT Events detector models, allowing you to execute complex logic, interact with external services, and implement sophisticated event handling.

AWS IoT Events uses a Lambda function to manage alarm notifications. You can use the Lambda function provided by AWS IoT Events or create a new one.

**Topics**
+ [Creating a Lambda function in AWS IoT Events](alarms-create-lambda.md)
+ [Using the Lambda function provided by AWS IoT Events](use-alarm-notifications.md)
+ [Manage IAM Identity Center access of alarm recipients in AWS IoT Events](sso-authorization-recipients.md)

# Creating a Lambda function in AWS IoT Events
<a name="alarms-create-lambda"></a>

AWS IoT Events provides a Lambda function that enables alarms to send and receive email and SMS notifications.

## Requirements
<a name="alarms-lambda-requirements"></a>

The following requirements apply when you create a Lambda function for alarms:
+ If your alarm sends SMS notifications, ensure Amazon SNS is configured to deliver SMS messages.
  + For more information, see the following documentation:
    + [Mobile text messaging with Amazon SNS](https://docs.aws.amazon.com/sns/latest/dg/sns-mobile-phone-number-as-subscriber.html) and [Origination identities for Amazon SNS SMS messages](https://docs.aws.amazon.com/sns/latest/dg/channels-sms-originating-identities.html) in the *Amazon Simple Notification Service Developer Guide*.
    + [What is AWS End User Messaging SMS?](https://docs.aws.amazon.com/sms-voice/latest/userguide/what-is-sms-mms.html) in the *AWS SMS User Guide*.
+ If your alarm sends email or SMS notifications, you must have an IAM role that allows AWS Lambda to work with Amazon SES and Amazon SNS.

  

  Example policy:

------
#### [ JSON ]

****  

  ```
  {
      "Version":"2012-10-17",		 	 	 
      "Statement": [
          {
              "Effect": "Allow",
              "Action": [
                  "ses:GetIdentityVerificationAttributes",
                  "ses:SendEmail",
                  "ses:VerifyEmailIdentity"
              ],
              "Resource": "*"
          },
          {
              "Effect": "Allow",
              "Action": [
                  "sns:Publish",
                  "sns:OptInPhoneNumber",
                  "sns:CheckIfPhoneNumberIsOptedOut",
                  "sms-voice:DescribeOptedOutNumbers"
              ],
              "Resource": "*"
          },
          {
              "Effect": "Deny",
              "Action": "sns:Publish",
              "Resource": "arn:aws:sns:*:*:*"
          },
          {
            "Effect" : "Allow",
            "Action" : [
              "logs:CreateLogGroup",
              "logs:CreateLogStream",
              "logs:PutLogEvents"
            ],
            "Resource" : "*"
          }
      ]
  }
  ```

------
+ You must choose the same AWS Region for both AWS IoT Events and AWS Lambda. For the list of supported Regions, see [AWS IoT Events endpoints and quotas](https://docs.aws.amazon.com/general/latest/gr/iot-events.html) and [AWS Lambda endpoints and quotas](https://docs.aws.amazon.com/general/latest/gr/lambda-service.html) in the *Amazon Web Services General Reference*.

# Deploy a Lambda function for AWS IoT Events using CloudFormation
<a name="alarms-create-lambda-cfn"></a>

This tutorial uses an CloudFormation template to deploy a Lambda function. This template automatically creates an IAM role that allows the Lambda function to work with Amazon SES and Amazon SNS.

The following shows you how to use the AWS Command Line Interface (AWS CLI) to create a CloudFormation stack.

1. <a name="install-cli"></a>In your device's terminal, run `aws --version` to check if you installed the AWS CLI. For more information, see [Installing or updating to the latest version of the AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) in the *AWS Command Line Interface User Guide*.

1. <a name="configure-cli"></a>Run `aws configure list` to check if you configured the AWS CLI in the AWS Region that has all your AWS resources for this tutorial. For more information, see [Set and view configuration settings using commands](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html#cli-configure-files-methods) in the *AWS Command Line Interface User Guide*

1. Download the CloudFormation template, [notificationLambda.template.yaml.zip](samples/notificationLambda.template.yaml.zip).
**Note**  
If you have difficulty downloading the file, the template is also available in the [CloudFormation template](alarms-create-lambda.md#cfn-template).

1. Unzip the content and save it locally as `notificationLambda.template.yaml`.

1. Open a terminal on your device and navigate to the directory where you downloaded the `notificationLambda.template.yaml` file.

1. To create a CloudFormation stack, run the following command:

   ```
   aws cloudformation create-stack --stack-name notificationLambda-stack --template-body file://notificationLambda.template.yaml --capabilities CAPABILITY_IAM
   ```

You might modify this CloudFormation template to customize the Lambda function and its behavior.

**Note**  
AWS Lambda retries function errors twice. If the function doesn't have enough capacity to handle all incoming requests, events might wait in the queue for hours or days to be sent to the function. You can configure an undelivered-message queue (DLQ) on the function to capture events that weren't successfully processed. For more information, see [Asynchronous invocation](https://docs.aws.amazon.com/lambda/latest/dg/invocation-async.html) in the *AWS Lambda Developer Guide*.

You can also create or configure the stack in the CloudFormation console. For more information, see [Working with stacks](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/stacks.html), in the *AWS CloudFormation User Guide*.

# Creating a custom Lambda function for AWS IoT Events
<a name="alarms-create-custom-lambda"></a>

You can create a Lambda function or modify the one provided by AWS IoT Events.

The following requirements apply when you create a custom Lambda function.
+ Add permissions that allow your Lambda function to perform specified actions and access AWS resources.
+ If you use the Lambda function provided by AWS IoT Events, make sure that you choose the Python 3.7 runtime.

Example Lambda function:

```
import boto3
import json
import logging
import datetime
logger = logging.getLogger()
logger.setLevel(logging.INFO)
ses = boto3.client('ses')
sns = boto3.client('sns')
def check_value(target):
  if target:
    return True
  return False

# Check whether email is verified. Only verified emails are allowed to send emails to or from.
def check_email(email):
  if not check_value(email):
    return False
  result = ses.get_identity_verification_attributes(Identities=[email])
  attr = result['VerificationAttributes']
  if (email not in attr or attr[email]['VerificationStatus'] != 'Success'):
      logging.info('Verification email for {} sent. You must have all the emails verified before sending email.'.format(email))
      ses.verify_email_identity(EmailAddress=email)
      return False
  return True

# Check whether the phone holder has opted out of receiving SMS messages from your account
def check_phone_number(phone_number):
  try:
    result = sns.check_if_phone_number_is_opted_out(phoneNumber=phone_number)
    if (result['isOptedOut']):
        logger.info('phoneNumber {} is not opt in of receiving SMS messages. Phone number must be opt in first.'.format(phone_number))
        return False
    return True
  except Exception as e:
    logging.error('Your phone number {} must be in E.164 format in SSO. Exception thrown: {}'.format(phone_number, e))
    return False

def check_emails(emails):
  result = True
  for email in emails:
      if not check_email(email):
          result = False
  return result

def lambda_handler(event, context):
  logging.info('Received event: ' + json.dumps(event))
  nep = json.loads(event.get('notificationEventPayload'))
  alarm_state = nep['alarmState']
  default_msg = 'Alarm ' + alarm_state['stateName'] + '\n'
  timestamp = datetime.datetime.utcfromtimestamp(float(nep['stateUpdateTime'])/1000).strftime('%Y-%m-%d %H:%M:%S')
  alarm_msg = "{} {} {} at {} UTC ".format(nep['alarmModelName'], nep.get('keyValue', 'Singleton'), alarm_state['stateName'], timestamp)
  default_msg += 'Sev: ' + str(nep['severity']) + '\n'
  if (alarm_state['ruleEvaluation']):
    property = alarm_state['ruleEvaluation']['simpleRule']['inputProperty']
    default_msg += 'Current Value: ' + str(property) + '\n'
    operator = alarm_state['ruleEvaluation']['simpleRule']['operator']
    threshold = alarm_state['ruleEvaluation']['simpleRule']['threshold']
    alarm_msg += '({} {} {})'.format(str(property), operator, str(threshold))
  default_msg += alarm_msg + '\n'

  emails = event.get('emailConfigurations', [])
  logger.info('Start Sending Emails')
  for email in emails:
    from_adr = email.get('from')
    to_adrs = email.get('to', [])
    cc_adrs = email.get('cc', [])
    bcc_adrs = email.get('bcc', [])
    msg = default_msg + '\n' + email.get('additionalMessage', '')
    subject = email.get('subject', alarm_msg)
    fa_ver = check_email(from_adr)
    tas_ver = check_emails(to_adrs)
    ccas_ver = check_emails(cc_adrs)
    bccas_ver = check_emails(bcc_adrs)
    if (fa_ver and tas_ver and ccas_ver and bccas_ver):
      ses.send_email(Source=from_adr,
                     Destination={'ToAddresses': to_adrs, 'CcAddresses': cc_adrs, 'BccAddresses': bcc_adrs},
                     Message={'Subject': {'Data': subject}, 'Body': {'Text': {'Data': msg}}})
      logger.info('Emails have been sent')

  logger.info('Start Sending SNS message to SMS')
  sns_configs = event.get('smsConfigurations', [])
  for sns_config in sns_configs:
    sns_msg = default_msg + '\n' + sns_config.get('additionalMessage', '')
    phone_numbers = sns_config.get('phoneNumbers', [])
    sender_id = sns_config.get('senderId')
    for phone_number in phone_numbers:
        if check_phone_number(phone_number):
          if check_value(sender_id):
            sns.publish(PhoneNumber=phone_number, Message=sns_msg, MessageAttributes={'AWS.SNS.SMS.SenderID':{'DataType': 'String','StringValue': sender_id}})
          else:
            sns.publish(PhoneNumber=phone_number, Message=sns_msg)
          logger.info('SNS messages have been sent')
```

For more information, see [What is AWS Lambda?](https://docs.aws.amazon.com/lambda/latest/dg/welcome.html) in the *AWS Lambda Developer Guide*.

## CloudFormation template
<a name="cfn-template"></a>

Use the following CloudFormation template to create your Lambda function.

```
AWSTemplateFormatVersion: '2010-09-09'
Description: 'Notification Lambda for Alarm Model'
Resources:
  NotificationLambdaRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: sts:AssumeRole
      Path: "/"
      ManagedPolicyArns:
        - 'arn:aws:iam::aws:policy/AWSLambdaExecute'
      Policies:
        - PolicyName: "NotificationLambda"
          PolicyDocument:
            Version: "2012-10-17"		 	 	 
            Statement:
              - Effect: "Allow"
                Action:
                  - "ses:GetIdentityVerificationAttributes"
                  - "ses:SendEmail"
                  - "ses:VerifyEmailIdentity"
                Resource: "*"
              - Effect: "Allow"
                Action:
                  - "sns:Publish"
                  - "sns:OptInPhoneNumber"
                  - "sns:CheckIfPhoneNumberIsOptedOut"
                  - "sms-voice:DescribeOptedOutNumbers"
                Resource: "*"
              - Effect: "Deny"
                Action:
                  - "sns:Publish"
                Resource: "arn:aws:sns:*:*:*"
  NotificationLambdaFunction:              
    Type: AWS::Lambda::Function
    Properties:
      Role: !GetAtt NotificationLambdaRole.Arn
      Runtime: python3.7
      Handler: index.lambda_handler
      Timeout: 300
      MemorySize: 3008
      Code:
        ZipFile: |
          import boto3
          import json
          import logging
          import datetime
          logger = logging.getLogger()
          logger.setLevel(logging.INFO)
          ses = boto3.client('ses')
          sns = boto3.client('sns')
          def check_value(target):
            if target:
              return True
            return False

          # Check whether email is verified. Only verified emails are allowed to send emails to or from.
          def check_email(email):
            if not check_value(email):
              return False
            result = ses.get_identity_verification_attributes(Identities=[email])
            attr = result['VerificationAttributes']
            if (email not in attr or attr[email]['VerificationStatus'] != 'Success'):
                logging.info('Verification email for {} sent. You must have all the emails verified before sending email.'.format(email))
                ses.verify_email_identity(EmailAddress=email)
                return False
            return True

          # Check whether the phone holder has opted out of receiving SMS messages from your account
          def check_phone_number(phone_number):
            try:
              result = sns.check_if_phone_number_is_opted_out(phoneNumber=phone_number)
              if (result['isOptedOut']):
                  logger.info('phoneNumber {} is not opt in of receiving SMS messages. Phone number must be opt in first.'.format(phone_number))
                  return False
              return True
            except Exception as e:
              logging.error('Your phone number {} must be in E.164 format in SSO. Exception thrown: {}'.format(phone_number, e))
              return False

          def check_emails(emails):
            result = True
            for email in emails:
                if not check_email(email):
                    result = False
            return result

          def lambda_handler(event, context):
            logging.info('Received event: ' + json.dumps(event))
            nep = json.loads(event.get('notificationEventPayload'))
            alarm_state = nep['alarmState']
            default_msg = 'Alarm ' + alarm_state['stateName'] + '\n'
            timestamp = datetime.datetime.utcfromtimestamp(float(nep['stateUpdateTime'])/1000).strftime('%Y-%m-%d %H:%M:%S')
            alarm_msg = "{} {} {} at {} UTC ".format(nep['alarmModelName'], nep.get('keyValue', 'Singleton'), alarm_state['stateName'], timestamp)
            default_msg += 'Sev: ' + str(nep['severity']) + '\n'
            if (alarm_state['ruleEvaluation']):
              property = alarm_state['ruleEvaluation']['simpleRule']['inputProperty']
              default_msg += 'Current Value: ' + str(property) + '\n'
              operator = alarm_state['ruleEvaluation']['simpleRule']['operator']
              threshold = alarm_state['ruleEvaluation']['simpleRule']['threshold']
              alarm_msg += '({} {} {})'.format(str(property), operator, str(threshold))
            default_msg += alarm_msg + '\n'

            emails = event.get('emailConfigurations', [])
            logger.info('Start Sending Emails')
            for email in emails:
              from_adr = email.get('from')
              to_adrs = email.get('to', [])
              cc_adrs = email.get('cc', [])
              bcc_adrs = email.get('bcc', [])
              msg = default_msg + '\n' + email.get('additionalMessage', '')
              subject = email.get('subject', alarm_msg)
              fa_ver = check_email(from_adr)
              tas_ver = check_emails(to_adrs)
              ccas_ver = check_emails(cc_adrs)
              bccas_ver = check_emails(bcc_adrs)
              if (fa_ver and tas_ver and ccas_ver and bccas_ver):
                ses.send_email(Source=from_adr,
                               Destination={'ToAddresses': to_adrs, 'CcAddresses': cc_adrs, 'BccAddresses': bcc_adrs},
                               Message={'Subject': {'Data': subject}, 'Body': {'Text': {'Data': msg}}})
                logger.info('Emails have been sent')

            logger.info('Start Sending SNS message to SMS')
            sns_configs = event.get('smsConfigurations', [])
            for sns_config in sns_configs:
              sns_msg = default_msg + '\n' + sns_config.get('additionalMessage', '')
              phone_numbers = sns_config.get('phoneNumbers', [])
              sender_id = sns_config.get('senderId')
              for phone_number in phone_numbers:
                  if check_phone_number(phone_number):
                    if check_value(sender_id):
                      sns.publish(PhoneNumber=phone_number, Message=sns_msg, MessageAttributes={'AWS.SNS.SMS.SenderID':{'DataType': 'String','StringValue': sender_id}})
                    else:
                      sns.publish(PhoneNumber=phone_number, Message=sns_msg)
                    logger.info('SNS messages have been sent')
```

# Using the Lambda function provided by AWS IoT Events
<a name="use-alarm-notifications"></a>

With alarm notifications, you can use the Lambda function provided by AWS IoT Events for managing alarm notifications.

The following requirements apply when you use the Lambda function provided by AWS IoT Events to manage your alarm notifications:
+ You must verify the email address that sends the email notifications in Amazon Simple Email Service (Amazon SES). For more information, see [Verifying an email address identity](https://docs.aws.amazon.com/ses/latest/dg/creating-identities.html#just-verify-email-proc), in the *Amazon Simple Email Service Developer Guide*.

  If you receive a verification link, click the link to verify your email address. You might also check your spam folder for a verification email.
+ If your alarm sends SMS notifications, you must use E.164 international phone number formatting for phone numbers. This format contains `+<country-calling-code><area-code><phone-number>`.

  Example phone numbers:    
[\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/iotevents/latest/developerguide/use-alarm-notifications.html)

  To find a country calling code, go to [countrycode.org](https://countrycode.org/).

  The Lambda function provided by AWS IoT Events checks if you use E.164 formatted phone numbers. However, it doesn't verify the phone numbers. If you ensure that you entered accurate phone numbers but didn't receive SMS notifications, you might contact the phone carriers. The carriers may block the messages.

# Manage IAM Identity Center access of alarm recipients in AWS IoT Events
<a name="sso-authorization-recipients"></a>

AWS IoT Events uses AWS IAM Identity Center to manage the SSO access of alarms recipients. Implementing IAM Identity Center for AWS IoT Events notification recipients can enhance security and user experience. To enable the alarm to send notifications to the recipients, you must enable IAM Identity Center and add recipients to your IAM Identity Center store. For more information, see [Add Users](https://docs.aws.amazon.com/singlesignon/latest/userguide/addusers.html) in *AWS IAM Identity Center User Guide*.

**Important**  
You must choose the same AWS Region for AWS IoT Events, AWS Lambda, and IAM Identity Center.
AWS Organizations only supports one IAM Identity Center Region at a time. If you want to make IAM Identity Center available in a different Region, you must first delete your current IAM Identity Center configuration. For more information, see [IAM Identity Center Region Data](https://docs.aws.amazon.com/singlesignon/latest/userguide/regions.html#region-data) in *AWS IAM Identity Center User Guide*.