49

I am trying to publish to an SNS topic which will then notify a Lambda function, as well as an SQS queue. My Lambda function does get called, but the CloudWatch logs state that my "event" object is None. The boto3 docs states to use the kwarg MessageStructure='json' but that throws a ClientError.

Hopefully I've supplied enough information.

Example Code:

import json
import boto3

message = {"foo": "bar"}
client = boto3.client('sns')
response = client.publish(
    TargetArn=arn,
    Message=json.dumps(message)
)
bmoran
  • 1,499
  • 2
  • 13
  • 21
  • 1
    You only need the ``MessageStructure`` param if you are trying to send different messages to different types of subscribers (e.g. email vs. SMS). Could you include the code for your Lambda function? I'm assuming that the code shown above works without any errors, right? – garnaat Dec 02 '15 at 14:00
  • 1
    If you're running this using the Python SDK on say an EC2-Instance don't forget to add a region inside the client e.g., `client = boto3.client('sns', region_name='us-east-1')` https://bradmontgomery.net/blog/sending-sms-messages-amazon-sns-and-python/ – Kyle Bridenstine May 18 '18 at 16:35

3 Answers3

107

you need to add a default key to your message payload, and specify MessageStructure:

import json
import boto3

message = {"foo": "bar"}
client = boto3.client('sns')
response = client.publish(
    TargetArn=arn,
    Message=json.dumps({'default': json.dumps(message)}),
    MessageStructure='json'
)
ryantuck
  • 6,146
  • 10
  • 57
  • 71
  • 1
    Your example doesn't include a default – Chris Johnson Oct 14 '16 at 00:25
  • 13
    sure it does - it's in the dict passed to the `Message` arg. – ryantuck Oct 14 '16 at 21:13
  • I don't understand what your message object is in terms of the foo bar stuff. What's a real example? `message = {"body": "Hello World!"}`? – Kyle Bridenstine May 18 '18 at 16:23
  • 3
    If you're running this using the Python SDK on say an EC2-Instance don't forget to add a region inside the client e.g., `client = boto3.client('sns', region_name='us-east-1')` https://bradmontgomery.net/blog/sending-sms-messages-amazon-sns-and-python/ – Kyle Bridenstine May 18 '18 at 16:35
  • Hi @RyanTuck, I wonder if we need to do this if we want to send SNS msg to SQS? I am aware that as per AWS instruction, in order to send a json message we may need to add MessageStructure. But even without this, the end result of message body is still the same for SQS. – addicted Dec 10 '19 at 20:30
  • 1
    @ryantuck Is the 2nd json.dumps() necessary at all? – Moshe Rabaev Jul 27 '20 at 18:20
  • @MosheRabaev I'm not sure now, I just know that it had worked four years ago when I tried this :) – ryantuck Jul 29 '20 at 19:28
40

Just in case you want to have different messages for sms and email subscribers:

import json
import boto3

message = {"foo": "bar"}
client = boto3.client('sns')
response = client.publish(
    TargetArn=arn,
    Message=json.dumps({'default': json.dumps(message),
                        'sms': 'here a short version of the message',
                        'email': 'here a longer version of the message'}),
    Subject='a short subject for your message',
    MessageStructure='json'
)
Amir
  • 5,996
  • 13
  • 48
  • 61
  • 4
    If you're running this using the Python SDK on say an EC2-Instance don't forget to add a region inside the client e.g., `client = boto3.client('sns', region_name='us-east-1')` https://bradmontgomery.net/blog/sending-sms-messages-amazon-sns-and-python/ – Kyle Bridenstine May 18 '18 at 16:35
  • help full in my case – Narendra Maru Jun 13 '19 at 13:05
5

In case you are publishing your message with a filter policy, you should also use MessageAttributes parameter to add your SNS filter.

To invoke your Lambda with this SNS subscription filter policy {"endpoint": ["distance"]}:

import json
import boto3

message = {"foo": "bar"}
client = boto3.client('sns')
response = client.publish(
    TargetArn=arn,
    Message=json.dumps({'default': json.dumps(message)}),
    MessageStructure='json',
    MessageAttributes={
                        'foo': {
                            'DataType': 'String',
                            'StringValue': 'bar'
                        }
                    },
)
Kerem
  • 1,494
  • 2
  • 16
  • 27