DEV Community

jasonmills94
jasonmills94

Posted on

Tie Terraform Apply Emails to One Change Set

Terraform apply emails are useful right until two pipelines overlap and nobody is sure which message belongs to which infrastructure change. That confusion shows up more often than teams admit. The email still arrives, the apply still completes, but the evidence trail gets fuzzy and ops people start doing guesswork they really shouldnt be doing.

The fix is not more email. The fix is attaching every notification to one reviewed change set and one pipeline run. If the message cannot tell you the workspace, commit, plan artifact, and approval window, it is just noise wearing a green checkmark.

Why Terraform apply emails become untrustworthy

Most drift starts with small shortcuts:

  • the email template reads the latest plan artifact instead of the approved one
  • one notification worker serves multiple environments with weak correlation fields
  • the apply step sends success before the post-apply verification finishes
  • the inbox used for validation is shared across several runs
  • retries produce two "success" emails with almost the same wording

That is how teams end up checking a fake e mail com inbox or a temp gamil com address by hand and calling it verification. It may be fast, but it is not durable. The real issue is not the inbox provider. The issue is that the pipeline never produced a stable receipt for the change it just applied.

I like the same discipline behind contract-test email checks in CI: define exactly what the message must prove, then verify that contract from one run's artifacts. For infrastructure notifications, the contract should be even tighter because approvals and rollbacks depend on it.

The change set receipt worth keeping

The simplest pattern is a small JSON receipt written after terraform plan and carried through approval and apply. Keep it boring. Boring systems are easier to trust when things get weird at 2 AM.

My recommended receipt fields are:

  • pipeline run ID
  • git commit SHA
  • Terraform workspace
  • plan file checksum
  • AWS account ID and region
  • change request or approval ID
  • apply start and finish timestamps

That receipt becomes the source for the email body, not whatever state the runner happens to see later. AWS has pushed this same kind of artifact-first thinking for delivery systems, especially around traceability and rollback-ready release workflows in the AWS Prescriptive Guidance for CI/CD pipelines.

What to validate before approval

When the email lands, I do not care only that it exists. I want it to prove the right change was applied. These are the checks worth automating:

  • subject includes the workspace and run ID
  • body includes the exact plan checksum
  • AWS account and region match the target environment
  • apply finished after the approval event, not before it
  • only one final success email exists for the approved run

That last one matters because retries can quietly create duplicate verdicts. Once there are two "done" messages, the team wastes time comparing timestamps and trying to remember which runner crashed first. It sounds small, but it gets messy fast.

This is also where log hygiene matters. If the workflow emits approval metadata or notification payloads, follow the same instincts used in safer auth event logging: store identifiers that help correlation, not raw secrets or blobs that create extra risk.

A small pipeline example

This is the shape I prefer:

RUN_ID="$(date -u +%Y%m%dT%H%M%SZ)"
PLAN_FILE="tfplan-${RUN_ID}.bin"
RECEIPT="apply-receipt-${RUN_ID}.json"

terraform plan -out "$PLAN_FILE"
PLAN_SHA="$(sha256sum "$PLAN_FILE" | awk '{print $1}')"

cat > "$RECEIPT" <<EOF
{"run_id":"$RUN_ID","workspace":"prod","plan_sha":"$PLAN_SHA","region":"ap-southeast-1"}
EOF

terraform apply "$PLAN_FILE"
./send-apply-email --receipt "$RECEIPT"
./verify-apply-email --receipt "$RECEIPT"
Enter fullscreen mode Exit fullscreen mode

It is not fancy, and that is the point. One receipt file, one plan checksum, one apply result. If a reviewer asks what changed, you have a clean answer instead of a sorta-related email thread and a half-remembered Slack message.

Common failure modes

These are the breakpoints I still see a lot:

  • storing only the plan filename instead of a checksum
  • rebuilding the plan during apply and assuming it is equivalent
  • sending the email before downstream smoke checks finish
  • mixing staging and production notifications in one validation path
  • throwing away the receipt once the pipeline is green

The checksum mistake is sneaky because the workflow still looks neat on paper. But filenames can be reused, artifacts can be replaced, and runners can rehydrate state in surprising ways. A checksum is not glamorous, it is just solid.

Q&A

Is this overkill for every Terraform run?

Yes for personal sandboxes, no for shared environments or anything with approvals. Use it where an email is acting as release evidence, not just a status update.

Why not trust CloudWatch or Terraform logs alone?

Because those prove the apply happened. They do not prove the human-facing email matched the approved change set. Those are seperate contracts, and both matter.

What is the first upgrade if the current pipeline is messy?

Write the receipt after terraform plan and include the plan checksum in the email. That one step fixes a surprizing amount of ambiguity before you redesign the rest.

Top comments (0)