• Home
  • Testimonials
  • Blog
  • Contact Us

At a Glance of a Key

Crafting Dreams into Ventures, Code into Excellence: Your Journey to Success

  • Home
  • Testimonials
  • Blog
  • Contact Us

Serverless On-call duty notifier – Part 2

2017-07-24 Development No Comments 3 minute read

In the previous blog post, I’ve described how to build a simple SMS notification system using DynamoDB, SNS and AWS Lambda. In this post, I’ll show how to change it in order to allow each user to choose whenever he wants to get SMS notification, Email notification or nothing at all.

First of all we need to change the users table layout and add 2 additional fields to each user row. The script that is shown in the previous post for filling the database should look like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import boto3

dynamodb = boto3.resource("dynamodb")

if __name__ == "__main__":
    users = dynamodb.Table("oncall-notifier.names")
    with users.batch_writer() as batch:
        batch.put_item(Item={"Name": "Alexander", "Phone": "+972000000000", "Email": "[email protected]", "Preferred": "SMS,Email"})
        batch.put_item(Item={"Name": "Danny", "Phone": "+972000000000", "Email": "[email protected]", "Preferred": "Email"})
        batch.put_item(Item={"Name": "Moshe", "Phone": "+972000000000", "Email": "[email protected]", "Preferred": "None"})

    dates = dynamodb.Table("oncall-notifier.dates")
    with dates.batch_writer() as batch:
        batch.put_item(Item={"Date": "2017-06-28", "Names": ["Alexander", "Danny"]})
        batch.put_item(Item={"Date": "2017-06-29", "Names": ["Alexander", "Moshe"]})
        batch.put_item(Item={"Date": "2017-06-30", "Names" : ["Danny", "Moshe"]})

As you can see, each user has 4 fields: Name, Phone, Email, Preferred. The “Preferred” field can contain the following values: “Email”, “SMS”, “None” and can combine them using comma (for example: “SMS,Email”).

For sending emails, we’ll use the AWS SES (Amazon Simple Email Service) service. In order to confirm that we really own the domain we’re sending emails to/from, we need to verify it. We simply go to the SES page, add a new domain and get some lines we need to add to our domains DNS DKIM settings. The domain verification should take 5 minutes and we’re ready to go.

Sending email with SES is done simply by using boto3 SDK for python. There are multiple options that we can use (Plain text/HTML/CC/BCC/etc.) that can be found in the boto3 documentation page.

We’ll try to keep it simple and send a simple plain text message.

1
2
3
4
5
6
7
8
ses = boto3.client("ses")
message = "On-call for today - %s" % ", ".join(people)
ses.send_email(Source="[email protected]",
               Destination={ "ToAddresses": [ item["Email"] ] },
               Message={
                    "Subject": { "Data": "Company On-Call Duty" },
                    "Body": { "Text": { "Data": message }}
               })

When we read the user’s details from the database, we need to check his preferred notification way and act accordingly. The full lambda code should look like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
from __future__ import print_function

import boto3
import datetime
import sys

def get_today_duty(dynamodb):
        today = str(datetime.datetime.now().date())
        print("Querying database for date: %s" % today)

        # Get todays people from dates table
        dates = dynamodb.Table("oncall-notifier.dates")

        response = dates.get_item(Key={ "Date" : today })
        if not("Item" in response.keys()):
                print("Failed with response:  %s" % response)
                return []

        item = response["Item"]["Names"]
        print("Found entry: %s" % item)
        return item

def get_details(dynamodb, people):
        users = dynamodb.Table("oncall-notifier.names")

        result = []
        for name in people:
                print("Querying user information for %s" % name)
                response = users.get_item(Key={ "Name" : name })
                if not ("Item" in response.keys()):
                        print("Failed with response:  %s" % response)
                        continue

                result.append(response["Item"])

        return result

def send_messages(message, people, items):
        sns = boto3.client("sns")
        ses = boto3.client("ses")

        for item in items:
                for preferred in item["Preferred"].lower().split(","):
                        try:
                            if preferred == "sms":
                                    print("Sending to %s using phone number: %s" % (item["Name"], item["Phone"]))
                                    sns.publish(Message=message, PhoneNumber=item["Phone"])
                            elif preferred == "email":
                                    print("Sending to %s using email: %s" % (item["Name"], item["Email"]))
                                    ses.send_email(Source="[email protected]",
                                                    Destination={
                                                            "ToAddresses": [ item["Email"] ]
                                                    },
                                                    Message={
                                                            "Subject": { "Data": "On-Call Duty Notifier" },
                                                            "Body": { "Text": { "Data": message }}
                                                    })
                            else:
                                    print("Not sending to %s" % item["Name"])
                        except Exception as e:
                            print("Caught exception: %s" % e.message)

def lambda_handler(event, context):
        dynamodb = boto3.resource("dynamodb")
        people = get_today_duty(dynamodb)
        if len(people) == 0:
                sys.exit(1)

        details = get_details(dynamodb, people)
        if len(details) == 0:
                sys.exit(1)

        message = "On-call for today - %s" % ", ".join(people)
        send_messages(message, people, details)

Feel free to use and extend it with more interesting ways of communication.

– Alexander

Oh hi there 👋
It’s nice to meet you.

Sign up to receive a notification when new posts are published!

We don’t spam!

Check your inbox or spam folder to confirm your subscription.

AWSCloudPythonServerless

Serverless On-call duty notifier - Part 1

SQS Benchmark (with large messages)

Leave a Reply Cancel reply

About Me

Principal Software Engineer and an industry leader with startup and FAANG experience. I specialize in distributed systems, storage, data protection services and payment processors.

Beyond technical expertise, I am passionate about supporting fellow engineers in their careers. Through approachable blogs and hands-on guidance, I help navigate the ever-evolving landscape of technology, empowering individuals to thrive in their professional journeys.

Open LinkedIn

Recent Posts

  • Building a Delayed Message System with Redis and FastAPI
  • Go Concurrency, Practical Example
  • Using GORM – Part 3: Models and Idempotency
  • Using GORM – Part 2: Transactions and Save Points
  • Using GORM – Part 1: Introduction

Archives

  • January 2025
  • December 2024
  • March 2023
  • February 2023
  • September 2022
  • July 2022
  • July 2021
  • June 2021
  • February 2021
  • April 2018
  • March 2018
  • January 2018
  • July 2017
  • June 2017
  • May 2017

Categories

  • AWS
  • Career Growth
  • Cyber Security
  • Debugging
  • Development
  • Storage
  • Tips & Tricks

Tags

API AWS Azure Bash Brainfuck C++ Challenge Cloud Cloud Bursting Concurrency Database DevOps Disassembly DLL Documentation DynamoDB Go Golang Guice Java Jenkins Mossad NoSQL OOP Performance Programming Python Redis Security Serverless Singleton Streams Testing Unit Tests WebService

All Rights Reserved 2025 © Sirotin Enterprises Inc.
Proudly powered by WordPress | Theme: Doo by ThemeVS.