From missed flight to mission: building a 24-hour reminder service on AWS

Published: (November 29, 2025 at 04:19 PM EST)
3 min read
Source: Dev.to

Source: Dev.to

🛠️ Stack

  • Data: DynamoDB table storing appointments (Name, Date, Time).
  • Compute: AWS Lambda scans the table, determines which appointments need a reminder.
  • Notify: Amazon SNS publishes email/SMS notifications.

Step‑by‑Step Walkthrough

1. Create the DynamoDB Table

PropertyValue
Table nameAppointment
Primary keyPartition key = Name (String)
AttributesName – e.g., “Dentist Visit”
Date – ISO string, e.g., 2025-12-29
Time – optional, 24‑hour format (HH:mm)

You can add additional attributes (e.g., UserEmail) if you want per‑user notifications.

2. Create the SNS Topic and Subscribe

  1. Open Amazon SNSTopicsCreate topic.
  2. Topic name: AppointmentReminders (Standard).
  3. Copy the Topic ARN – you’ll need it in the Lambda code.
  4. Add a subscription:
    • Protocol: Email (or SMS).
    • Endpoint: your email address (or phone number).
  5. Confirm the subscription via the link sent by AWS.

3. Create the Lambda Function (Node.js)

Configuration

  • Runtime: Node.js 18.x
  • Handler: index.handler
  • Memory / Timeout: 128 MB, 30 seconds (adjust as needed)

index.js

// index.js
const { DynamoDBClient, ScanCommand } = require("@aws-sdk/client-dynamodb");
const { SNSClient, PublishCommand } = require("@aws-sdk/client-sns");

// Environment variables (set in Lambda console)
const TABLE_NAME = process.env.APPOINTMENT_TABLE;
const SNS_TOPIC_ARN = process.env.SNS_TOPIC_ARN;

const ddb = new DynamoDBClient({});
const sns = new SNSClient({});

exports.handler = async () => {
  // 1️⃣ Scan the Appointment table
  const scanParams = {
    TableName: TABLE_NAME,
    ProjectionExpression: "Name, #d, #t, Email",
    ExpressionAttributeNames: {
      "#d": "Date",
      "#t": "Time"
    }
  };

  const data = await ddb.send(new ScanCommand(scanParams));

  // 2️⃣ Determine which items are within the next 24 h
  const now = new Date();
  const next24h = new Date(now.getTime() + 24 * 60 * 60 * 1000);

  const reminders = data.Items.filter(item => {
    const dateStr = item.Date.S;               // e.g. "2025-12-29"
    const timeStr = item.Time?.S || "00:00";   // optional, default midnight
    const apptDate = new Date(`${dateStr}T${timeStr}:00Z`);
    return apptDate > now && apptDate <= next24h;
  });

  // 3️⃣ Publish a reminder for each upcoming appointment
  for (const appt of reminders) {
    const message = `Reminder: ${appt.Name.S} on ${appt.Date.S} at ${appt.Time?.S || "00:00"}.`;
    const publishParams = {
      TopicArn: SNS_TOPIC_ARN,
      Message: message,
      Subject: "24‑hour Appointment Reminder",
      MessageAttributes: {
        "email": {
          DataType: "String",
          StringValue: appt.Email?.S || ""
        }
      }
    };
    await sns.send(new PublishCommand(publishParams));
  }

  return {
    statusCode: 200,
    body: `Sent ${reminders.length} reminder(s).`
  };
};

Environment variables to set in the Lambda console

VariableValue
APPOINTMENT_TABLEAppointment
SNS_TOPIC_ARNARN of the AppointmentReminders topic

4. IAM Permissions for Lambda

Attach an inline policy (or a managed policy) to the Lambda execution role that allows:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "dynamodb:Scan",
        "dynamodb:Query",
        "dynamodb:GetItem"
      ],
      "Resource": "arn:aws:dynamodb:*:*:table/Appointment"
    },
    {
      "Effect": "Allow",
      "Action": "sns:Publish",
      "Resource": "arn:aws:sns:*:*:AppointmentReminders"
    }
  ]
}

5. Add a Test Item in DynamoDB

NameDateTimeEmail
Dentist Visit2025-12-2909:00your.email@example.com

You can add the item via the DynamoDB console or the AWS CLI:

aws dynamodb put-item \
  --table-name Appointment \
  --item '{"Name":{"S":"Dentist Visit"},"Date":{"S":"2025-12-29"},"Time":{"S":"09:00"},"Email":{"S":"your.email@example.com"}}'

6. Test the Lambda

  1. In the Lambda console, click Test and create a simple event (the function doesn’t use the payload).
  2. Run the test.
  3. Check your email (or SMS) – you should receive a message like:
Subject: 24‑hour Appointment Reminder
Message: Reminder: Dentist Visit on 2025-12-29 at 09:00.

If you see the email, the end‑to‑end flow works.

🚀 What I learned

  • Forgetting is easy; systems aren’t. A tiny serverless stack can reliably give you a heads‑up.
  • 24‑hour timing provides enough buffer to prepare without being intrusive.
  • You don’t need a massive platform—just a DynamoDB table, a Lambda function, an SNS topic, and a scheduled trigger (e.g., CloudWatch Events / EventBridge) to run the Lambda once a day.
  • Building this project cemented core DevOps / Cloud Engineering skills: IAM least‑privilege policies, Lambda development, DynamoDB data modeling, and SNS notifications.

That’s the whole reminder service—simple, cheap, and effective. Happy building!

Back to Blog

Related posts

Read more »