Minimum Viable Release Notifications with AWS

8 min read

How a small project team can notify stakeholders of new releases, with minimal effort.


I can still recall working in a 10 person software team.

Every release was meticulously planned and could not fail. Hence, the developers often feared screwing it up. There was a big SOP we had to follow.

One of the items was to send an email after a new version was live.

This email was triple-checked, because it went out to the CEO. And yet, it was often done wrong. Typos and wrong version numbers often happened.

old email

This took a lot of brain power from the developers.

Can we automate this?

Our mission in making Cliptill is to document the process. We apply management in public, meaning we show all the surrounding activities in order to bring a new project online.

screenshot of cliptill

For releases, we want to have the simplest solution possible.

This is what we need:

  1. Release notifications are sent via email.
  2. Automatic triggers after versions being deployed
  3. We use AWS Lambda, no hosting required.

Just simple solution can be set up in 2-4 hours. It cost almost nothing to host, and almost doesn’t need maintenanance.

The end result

After every deploy we get emails like this:

This is an email whenvere we deploy on our preview system. We only send this to the dev team.

preview email

This is the email that goes out to other stakeholders and the marketing team.

live email

I am working on a YouTube video with better explanations. You can also ask your developer to use this post as a starting point. I’m adding the code snippets below.

Hopefully this helps a couple of people get better with their release management.

How did your last project team run releases? Please leave a comment on linkedin or Youtube!


P.S. I’m not certified in AWS. This is a minimal thing that works for us, and we are probably violating some best practices. Especially secret management and authentication is not done perfect. I’m posting this anyway and will make a v2 once I get feedback from AWS devs. Thanks!


AWS Lambda

Copy this into a lambda function. You also need an authenticated email domain in Simple Email Service.

import json
import boto3
import os
import logging

# Initialize logger
logger = logging.getLogger()

def lambda_handler(event, context):
    try:"---------------------------------")"Received event: {event}")

        # Parse the JSON body from the event
        body = event.get('body', '{}')
        if isinstance(body, str):
            body = json.loads(body)

        # Validate the token
        if os.environ.get('SECRET_TOKEN') != body.get('token'):
            raise ValueError("Invalid token")

        # Extract appname, version and tag
        appname = body.get('appname', 'Unknown App')
        version = body.get('version', 'Unknown Version')
        tag = body.get('tag')
        display_version = tag if tag else (version[:7] if version and len(version) > 7 else version)

        # Build email body from key-value pairs, excluding appname and version
        email_body = "Deployment Details:\n\n"
        for key, value in body.items():
            if key not in ['appname', 'version', 'token', 'recipients']:
                email_body += f"{key}: {value}\n"

        recipients_str = body.get('recipients', '')

        # Convert recipients string to a list
        if recipients_str and isinstance(recipients_str, str):
            recipients = recipients_str.split(',')
            raise ValueError("No valid recipients given")"New version of {appname} released: {recipients}")

        ses_client = boto3.client('ses')
        response = ses_client.send_email(
            Destination={'ToAddresses': recipients},
                'Subject': {'Data': f'Version {display_version} of {appname} deployed.'},
                'Body': {'Text': {'Data': email_body}}

        return {
            'statusCode': 200,
            'body': json.dumps('Email sent successfully!')

    except Exception as e:
        logger.error(f"Got exception: {e}")
        return {
            'statusCode': 500,
            'body': json.dumps(f'Error: {str(e)}')

The Lambda also needs environment variables

# Make sure to change this. Else someone could use your endpoint to spam people.
NOTIFIER_EMAIL=[email protected]

Add a policy

Make a policy to give the lambda function access to SES

Choose any name, like AuthorizeSESPairingDeployNotifier

Make sure to replace the “Resource” section with your SES email, and adjust the email address accordingly.

    "Version": "2012-10-17",
    "Statement": [
            "Sid": "VisualEditor0",
            "Effect": "Allow",
            "Action": [
            "Resource": "arn:aws:ses:us-east-1:151345295272518:identity/",
            "Condition": {
                "StringEquals": {
                    "ses:FromAddress": "[email protected]"

Finally test it in Insomnia.

insomnia screenshot

Once it works, add this to your pipeline.

Gitlab CI

Copy this into your .gitlab-ci.yml:

  stage: deploy
    - apk add --no-cache curl
    - COMMIT_MESSAGE=$(echo "$CI_COMMIT_MESSAGE" | sed 's/"/\"/g' | tr -d '\n')
    - PIPELINE_URL=$(echo "$CI_PIPELINE_URL" | sed 's/"/\"/g')
    - >
      -H "Content-Type: application/json"
      -d '{
            "token": "'"${DEPLOY_NOTIFICATION_TOKEN}"'",
            "appname": "'"${CI_PROJECT_NAME}"'",
            "version": "'$CI_COMMIT_SHA'",
            "message": "'"${COMMIT_MESSAGE}"'",
            "pipeline_url": "'"${PIPELINE_URL}"'",
            "deployment_time": "'"$(date -u)"'",
            "author": "'"${CI_COMMIT_AUTHOR}"'",
            "branch_name": "'"${CI_COMMIT_REF_NAME}"'",
            "environment_name": "'"${CI_ENVIRONMENT_NAME}"'",
            "recipients": "'$DEPLOY_NOTIFICATION_RECIPIENTS'"
    - deploy_production

And set these environment variables:

DEPLOY_NOTIFICATION_RECIPIENTS=[email protected],[email protected]

Till Carlos

I'm Till, a senior developer who started a software company. I explain software concepts for people in leading roles.