Skip to content

Latest commit

Β 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸ”· Dynatrace Email Notification Terraform Module

Manages a single Dynatrace email problem-notification configuration (dynatrace_email_notification) β€” recipients, subject/body templates, and the alerting profile it attaches to β€” for provider dynatrace-oss/dynatrace ~> 1.98.

Terraform Dynatrace Provider Module Version Module Type Resources Posture


🧩 Overview

  • Manages exactly one dynatrace_email_notification resource β€” a Settings 2.0-backed problem notification channel (schemaId builtin:problem.notifications).
  • Configures the primary (to), carbon-copy (cc), and blind-carbon-copy (bcc) recipient sets, each a set(string) of email addresses.
  • Configures the subject and body templates using Dynatrace's problem-notification placeholder syntax ({ProblemTitle}, {ProblemDetailsText}, {State}, etc.).
  • Attaches to an existing alerting profile by ID via the profile input β€” this module never creates or manages the alerting profile itself.
  • Ships secure by default: active defaults to false, so a newly-applied integration cannot send email until a caller explicitly reviews and enables it.

πŸ’‘ Why it matters: email is frequently the fallback notification channel every Dynatrace environment configures first, and often the one every team assumes "just works" once wired to a distribution list. A typed set(string) recipient model and a secure-by-default active flag turn two common failure modes β€” a typo'd recipient string silently accepted at plan time, and a freshly applied channel paging people before its content has been reviewed β€” into either a type error the planner catches or a deliberate opt-in the caller has to type.


❀️ Support this project

If these Terraform modules have been helpful to you or your organization, I'd appreciate your support in any of the following ways:

Whether it's a star, a professional connection, or a coffee, every gesture helps keep these modules actively maintained and continually improving. Thank you for being part of the community!


πŸ—ΊοΈ Where this fits

flowchart LR
 AP["terraform-dynatrace-alerting-profile"]:::sibling
 EN["terraform-dynatrace-email-notification"]:::thismodule
 RES["dynatrace_email_notification"]:::keystone

 AP -- "id β†’ profile" --> EN
 EN -- "provisions" --> RES

 classDef thismodule fill:#1496FF,color:#FFFFFF,stroke:#0A2540,stroke-width:1px;
 classDef keystone fill:#0A2540,color:#FFFFFF,stroke:#0A2540,stroke-width:1px;
 classDef sibling fill:#E5E7EB,color:#0A2540,stroke:#9CA3AF,stroke-width:1px;
Loading

This module consumes an alerting profile's id output (from terraform-dynatrace-alerting-profile) and provisions the email notification channel that fires against it. It has no children of its own and no other sibling module consumes its outputs by id β€” it sits at the end of the notification-channel family's dependency chain, not in the middle of it. (Diagram validated via the Mermaid Chart MCP β€” valid: true.)


🧬 What this builds

flowchart LR
 subgraph Inputs["Inputs (variables.tf)"]
 name["name"]
 profile["profile"]
 subject["subject"]
 body["body"]
 to["to"]
 cc["cc"]
 bcc["bcc"]
 ncp["notify_closed_problems"]
 active["active"]
 end

 RES["dynatrace_email_notification.this"]:::keystone

 name --> RES
 profile --> RES
 subject --> RES
 body --> RES
 to --> RES
 cc --> RES
 bcc --> RES
 ncp --> RES
 active --> RES

 RES -- "id" --> OUT_ID["output: id"]
 RES -- "name" --> OUT_NAME["output: name"]

 classDef keystone fill:#0A2540,color:#FFFFFF,stroke:#0A2540,stroke-width:1px;
Loading

(Diagram validated via the Mermaid Chart MCP β€” valid: true.)

Resource inventory:

  • dynatrace_email_notification.this β€” the sole resource. No for_each-driven children, no nested dynamic blocks β€” the live schema for this resource has no block_types at all, so main.tf is a direct, flat 1:1 attribute pass-through.

βœ… Provider / Versions

Component Requirement
Terraform >= 1.12.0
Provider dynatrace-oss/dynatrace ~> 1.98 (confirmed against the live schema at provider v1.100.0)
Provider block None β€” no provider "dynatrace" {} in this module; the caller configures auth and dt_env_url outside it

Schema notes that bite:

  • This is the only channel in the notification family with no provider-flagged sensitive fields. Confirmed against the live schema: dynatrace_email_notification has no secret/token/webhook-URL attribute of any kind β€” recipients are plain email-address strings. Contrast with sibling channels such as Slack (webhook URL), PagerDuty/OpsGenie (integration key), or ServiceNow (credentials), each of which carries at least one field this house standard requires treating as sensitive.
  • active has no provider-documented default β€” this module defaults the variable to false so a newly-applied integration does not fire before review. This is a module-level secure default, not a provider default; the provider itself simply leaves the behavior undocumented when the argument is entirely absent.
  • to is required and typed set(string) (the provider's own TypeSet of strings) β€” not a list, and not a comma-joined string. Order is not significant and duplicate addresses within the same field are collapsed by Terraform before the resource is ever created or updated.
  • cc and bcc are optional, also typed set(string), and default to [] in this module β€” omitting them produces no CC/BCC recipients, matching the provider's own "absent means none" behavior.
  • subject and body are both confirmed required strings on the live schema β€” an earlier scaffolding assumption that body might be optional does not hold; there is no fallback template.
  • notify_closed_problems is optional with no provider-documented default; this module leaves it at null, which omits the argument from the rendered resource block entirely rather than guessing true or false. Verify the resulting server-side behavior in a non-production environment if deterministic open/close notification behavior matters, and set it explicitly rather than relying on the omission.
  • The resource also exposes a computed legacy_id attribute (its Config API V1 cross-reference id). This module does not surface it as an output β€” it is provider interop metadata, not a caller-facing value.

πŸ”‘ Required OAuth Scopes / API Token Permissions

This module manages dynatrace_email_notification, a Settings 2.0-backed resource. It accepts either OAuth client credentials or a legacy API token.

  • API token (confirmed via the live provider documentation, v1.100.0): the provider's own resource page states explicitly β€” "This resource requires the API token scopes Read settings (settings.read) and Write settings (settings.write)." Grant a legacy API token exactly these two scopes.
  • OAuth (recommended): grant the OAuth client's IAM policy the equivalent Settings 2.0 scope pair, settings:objects:read and settings:objects:write, consistent with this domain's other Settings-2.0-backed resources (e.g. dynatrace_alerting, which documents the identical settings.read/settings.write API-token scope pair at the same provider version). The provider's resource-level page for dynatrace_email_notification documents only the API-token scope names explicitly β€” the OAuth scope-pair mapping follows this module suite's general Settings 2.0 auth convention rather than an explicit per-resource OAuth scope list in the provider's own docs. Verify against your environment's IAM policy model before a production apply.
  • This module does not touch IAM or Automation resources, so no account-idm-* or automation:* scopes are required.

Dynatrace Prerequisites

  • An OAuth client (or legacy API token) provisioned with the scopes/permissions above, bound via an IAM policy (OAuth) or token permissions (API token).
  • The target alerting profile must already exist (or be created in the same plan via an implicit reference to a terraform-dynatrace-alerting-profile instance's id output) β€” this module only references it by id and does not create or manage it.
  • Settings 2.0 schema availability (builtin:problem.notifications) for the target environment tier.

πŸ“ Module Structure

terraform-dynatrace-email-notification/
β”œβ”€β”€ providers.tf # required_version, required_providers pin β€” no provider {} block
β”œβ”€β”€ variables.tf # name, profile, subject, body, to, cc, bcc, notify_closed_problems, active
β”œβ”€β”€ main.tf # dynatrace_email_notification.this β€” thin, total, single-resource renderer
β”œβ”€β”€ outputs.tf # id, name
β”œβ”€β”€ README.md # this file
β”œβ”€β”€ SCOPE.md # lightweight cross-module contract
└── examples/
 └── quickstart/
 └── main.tf

βš™οΈ Quick Start

module "email_notification" {
  source = "git::https://github.com/microsoftexpert/terraform-dynatrace-email-notification.git?ref=v1.0.0"

  name    = "Email - Platform Team - Critical Problems"
  profile = "e5d24d1e-de08-4738-89bd-1a1dc9377b71" # existing dynatrace_alerting profile ID
  subject = "{ProblemSeverity} problem {ProblemID}: {ProblemTitle}"
  body    = "{ProblemDetailsText}"
  to      = ["oncall-platform@example.com"]
}

The caller configures the dynatrace provider (OAuth client credentials, platform token, or legacy API token, plus dt_env_url) once, outside this module. This module declares no provider {} block and no auth-related variables.


πŸ”Œ Cross-Module Contract

Consumes

Input Type Source module
profile string, required terraform-dynatrace-alerting-profile (its id output)

Emits

Output Description Consumed by
id The Dynatrace settings-object ID of this email notification configuration Reference only β€” no sibling module in this catalog consumes this by id
name The display name of this email notification configuration, as configured via var.name Documentation/reference only

πŸ“š Example Library

1 Β· Minimal inert integration (secure-by-default)
module "email_notification_inert" {
  source = "git::https://github.com/microsoftexpert/terraform-dynatrace-email-notification.git?ref=v1.0.0"

  name    = "Email - Platform Team - Critical Problems"
  profile = "e5d24d1e-de08-4738-89bd-1a1dc9377b71" # existing dynatrace_alerting profile ID
  subject = "{ProblemSeverity} problem {ProblemID}: {ProblemTitle}"
  body    = "{ProblemDetailsText}"
  to      = ["oncall-platform@example.com"]
}

πŸ”’ active is omitted here, so it defaults to false β€” the configuration is created but sends nothing until it is explicitly reviewed and turned on (Example 2).

2 Β· Activating a reviewed integration
module "email_notification_active" {
  source = "git::https://github.com/microsoftexpert/terraform-dynatrace-email-notification.git?ref=v1.0.0"

  name    = "Email - Platform Team - Critical Problems"
  profile = "e5d24d1e-de08-4738-89bd-1a1dc9377b71"
  subject = "{ProblemSeverity} problem {ProblemID}: {ProblemTitle}"
  body    = "{ProblemDetailsText}"
  to      = ["oncall-platform@example.com"]
  active  = true
}

⚠️ Set active = true only after subject, body, and recipients have been reviewed β€” a newly enabled email integration begins firing on the next matching problem.

3 Β· Multi-recipient (to/cc/bcc) integration
module "email_notification_multi_recipient" {
  source = "git::https://github.com/microsoftexpert/terraform-dynatrace-email-notification.git?ref=v1.0.0"

  name    = "Email - Platform Team - Critical Problems (Escalation)"
  profile = "e5d24d1e-de08-4738-89bd-1a1dc9377b71"
  subject = "{ProblemSeverity} problem {ProblemID}: {ProblemTitle}"
  body    = "{ProblemDetailsText}"
  to      = ["oncall-platform@example.com", "sre-team@example.com"]
  cc      = ["escalation-manager@example.com"]
  bcc     = ["compliance-archive@example.com"]
  active  = true
}

ℹ️ to, cc, and bcc are each modeled as set(string) (the provider's own TypeSet type) β€” order is not significant, and an address is only deduplicated within the field it's listed in, not across fields. An address present in both to and cc receives two separate copies from Dynatrace.

4 Β· Distribution lists, not personal inboxes
module "email_notification_distribution_list" {
  source = "git::https://github.com/microsoftexpert/terraform-dynatrace-email-notification.git?ref=v1.0.0"

  name    = "Email - Data Platform - Critical Problems"
  profile = "0987654321fedcba0987654321fedcba"
  subject = "{ProblemSeverity} problem {ProblemID}: {ProblemTitle}"
  body    = "{ProblemDetailsText}"
  to      = ["data-platform-oncall@example.com"]
  active  = true
}

πŸ’‘ Point to/cc/bcc at organizational alerting distribution lists or shared mailboxes, not individual employees' personal inboxes β€” this keeps the channel functional through on-call rotations and staffing changes without a Terraform change.

5 Β· Notify on both open and close
module "email_notification_notify_on_close" {
  source = "git::https://github.com/microsoftexpert/terraform-dynatrace-email-notification.git?ref=v1.0.0"

  name                   = "Email - Platform Team - Problem Lifecycle"
  profile                = "e5d24d1e-de08-4738-89bd-1a1dc9377b71"
  subject                = "[{State}] {ProblemSeverity} problem {ProblemID}: {ProblemTitle}"
  body                   = "{ProblemDetailsText}"
  to                     = ["oncall-platform@example.com"]
  notify_closed_problems = true
  active                 = true
}

ℹ️ The {State} placeholder in the subject line resolves to OPEN or RESOLVED, distinguishing the two emails a recipient now receives per problem lifecycle.

6 Β· Explicitly suppress close notifications
module "email_notification_open_only" {
  source = "git::https://github.com/microsoftexpert/terraform-dynatrace-email-notification.git?ref=v1.0.0"

  name                   = "Email - Platform Team - Open Problems Only"
  profile                = "e5d24d1e-de08-4738-89bd-1a1dc9377b71"
  subject                = "{ProblemSeverity} problem {ProblemID}: {ProblemTitle}"
  body                   = "{ProblemDetailsText}"
  to                     = ["oncall-platform@example.com"]
  notify_closed_problems = false
  active                 = true
}

ℹ️ Leaving notify_closed_problems unset (the module's null default) defers to whatever the Dynatrace API applies server-side when the argument is absent β€” that behavior is not documented by the provider. Set it explicitly, as above, whenever deterministic open/close notification behavior matters.

7 Β· Compliance BCC archive
module "email_notification_compliance_archive" {
  source = "git::https://github.com/microsoftexpert/terraform-dynatrace-email-notification.git?ref=v1.0.0"

  name    = "Email - Core Banking Platform - Critical Problems"
  profile = "3fa1c9d2b7e04a6f8c5d1e2a9b7c4f60"
  subject = "{ProblemSeverity} problem {ProblemID}: {ProblemTitle}"
  body    = "{ProblemDetailsText}"
  to      = ["core-banking-oncall@example.com"]
  bcc     = ["compliance-archive@example.com"]
  active  = true
}

πŸ”’ Confirm with Compliance/Risk whether routing an unmonitored BCC archive mailbox of this kind falls under existing records-retention policy before enabling it for a regulated workload β€” this is a human decision this module does not make for you.

8 Β· Placeholder-rich subject line for triage
module "email_notification_triage_subject" {
  source = "git::https://github.com/microsoftexpert/terraform-dynatrace-email-notification.git?ref=v1.0.0"

  name    = "Email - Platform Team - Triage"
  profile = "e5d24d1e-de08-4738-89bd-1a1dc9377b71"
  subject = "{ProblemSeverity}/{ProblemImpact}: {ImpactedEntity} β€” {ProblemTitle} ({ProblemID})"
  body    = "{ProblemDetailsText}"
  to      = ["oncall-platform@example.com"]
  active  = true
}

πŸ’‘ Type { in the Dynatrace UI when drafting subject/body templates for placeholder autocomplete; this module passes the string through unmodified, so a typo'd placeholder name is rendered literally rather than substituted.

9 Β· Structured JSON body for downstream ingestion
module "email_notification_json_body" {
  source = "git::https://github.com/microsoftexpert/terraform-dynatrace-email-notification.git?ref=v1.0.0"

  name    = "Email - Automation Pipeline - Problem Feed"
  profile = "e5d24d1e-de08-4738-89bd-1a1dc9377b71"
  subject = "{ProblemSeverity} problem {ProblemID}: {ProblemTitle}"
  body    = "{ProblemDetailsJSONv2}"
  to      = ["problem-feed-parser@example.com"]
  active  = true
}

ℹ️ {ProblemDetailsJSONv2} renders the full Problems V2 API structure as the email body β€” useful when a downstream mail-processing rule or ingestion mailbox parses the body as structured data rather than displaying it to a human.

10 Β· Markdown body for chat-forwarded triage
module "email_notification_markdown_body" {
  source = "git::https://github.com/microsoftexpert/terraform-dynatrace-email-notification.git?ref=v1.0.0"

  name    = "Email - Platform Team - Markdown Digest"
  profile = "e5d24d1e-de08-4738-89bd-1a1dc9377b71"
  subject = "{ProblemSeverity} problem {ProblemID}: {ProblemTitle}"
  body    = "{ProblemDetailsMarkdown}"
  to      = ["oncall-platform@example.com"]
  active  = true
}

ℹ️ {ProblemDetailsMarkdown} is convenient when the receiving mailbox or a mail-to-chat bridge renders Markdown; use {ProblemDetailsHTML} instead for HTML-rendering mail clients, or {ProblemDetailsText} for the plainest-common-denominator case (see Example 1).

11 Β· Escalation CC chain
module "email_notification_escalation_cc" {
  source = "git::https://github.com/microsoftexpert/terraform-dynatrace-email-notification.git?ref=v1.0.0"

  name    = "Email - Payments Platform - Critical Problems"
  profile = "7c2e9f14a8b3d05e6f1a2c3b4d5e6f70"
  subject = "{ProblemSeverity} problem {ProblemID}: {ProblemTitle}"
  body    = "{ProblemDetailsText}"
  to      = ["payments-oncall@example.com"]
  cc      = ["payments-eng-manager@example.com", "payments-duty-manager@example.com"]
  active  = true
}

ℹ️ cc recipients receive every notification alongside to; use cc for stakeholders who need visibility without being the primary responder, and reserve to for the team actually expected to act.

12 Β· Per-environment routing (prod vs. non-prod)
locals {
  environments = {
    prod = {
      name    = "Email - Platform Team - Production Critical Problems"
      profile = "e5d24d1e-de08-4738-89bd-1a1dc9377b71"
      to      = ["oncall-platform@example.com"]
      active  = true
    }
    nonprod = {
      name    = "Email - Platform Team - Non-Production Problems"
      profile = "b4a6c8d0e2f4a6c8d0e2f4a6c8d0e2f4"
      to      = ["platform-team@example.com"]
      active  = false # reviewed on a slower cadence; left inert until confirmed
    }
  }
}

module "email_notification_by_environment" {
  for_each = local.environments
  source   = "git::https://github.com/microsoftexpert/terraform-dynatrace-email-notification.git?ref=v1.0.0"

  name    = each.value.name
  profile = each.value.profile
  subject = "{ProblemSeverity} problem {ProblemID}: {ProblemTitle}"
  body    = "{ProblemDetailsText}"
  to      = each.value.to
  active  = each.value.active
}

πŸ’‘ The module itself is a standalone primitive with no internal for_each β€” breadth at scale is achieved by for_each-ing the module block itself in the calling root module, keyed by a caller-chosen map key (never count), consistent with the house standard.

13 Β· Fleet of team channels via for_each
locals {
  team_channels = {
    platform = {
      profile = "e5d24d1e-de08-4738-89bd-1a1dc9377b71"
      to      = ["oncall-platform@example.com"]
    }
    data = {
      profile = "0987654321fedcba0987654321fedcba"
      to      = ["oncall-data@example.com"]
    }
    payments = {
      profile = "7c2e9f14a8b3d05e6f1a2c3b4d5e6f70"
      to      = ["payments-oncall@example.com"]
    }
  }
}

module "team_email_notifications" {
  for_each = local.team_channels
  source   = "git::https://github.com/microsoftexpert/terraform-dynatrace-email-notification.git?ref=v1.0.0"

  name    = "Email - ${title(each.key)} Team - Critical Problems"
  profile = each.value.profile
  subject = "{ProblemSeverity} problem {ProblemID}: {ProblemTitle}"
  body    = "{ProblemDetailsText}"
  to      = each.value.to
  active  = true
}

πŸ’‘ Each team's channel is independently addressable by its map key (module.team_email_notifications["payments"]) β€” adding or removing a team never renumbers the others.

14 Β· Minimal required-only call
module "email_notification_required_only" {
  source = "git::https://github.com/microsoftexpert/terraform-dynatrace-email-notification.git?ref=v1.0.0"

  name    = "Email - Sandbox - Test Notification"
  profile = "1a2b3c4d5e6f7a8b9c0d1e2f3a4b5c6d"
  subject = "{ProblemTitle}"
  body    = "{ProblemDetailsText}"
  to      = ["sandbox-test@example.com"]
}

ℹ️ Every argument here is required by the live provider schema except active, cc, bcc, and notify_closed_problems, all four of which fall back to their module defaults (false, [], [], and null respectively).

15 Β· πŸ—οΈ End-to-end composition

Wires a terraform-dynatrace-alerting-profile instance's id output into this module's profile input β€” the shape every caller should use in practice, rather than hardcoding a profile ID.

module "critical_availability_profile" {
  source = "git::https://github.com/microsoftexpert/terraform-dynatrace-alerting-profile.git?ref=v1.0.0"

  name = "Critical Availability - Platform"

  rules = {
    availability-all-entities = {
      severity_level   = "AVAILABILITY"
      include_mode     = "INCLUDE_ALL"
      delay_in_minutes = 5
      tags             = ["Team:platform", "Environment:production"]
    }
  }
}

module "platform_email_notification" {
  source = "git::https://github.com/microsoftexpert/terraform-dynatrace-email-notification.git?ref=v1.0.0"

  name    = "Email - Platform Team - Critical Availability"
  profile = module.critical_availability_profile.id
  subject = "{ProblemSeverity} problem {ProblemID}: {ProblemTitle}"
  body    = "{ProblemDetailsText}"
  to      = ["oncall-platform@example.com"]
  cc      = ["escalation-manager@example.com"]
  active  = true
}

πŸ’‘ Referencing module.critical_availability_profile.id directly (instead of a literal string) gives Terraform an implicit reference, so the alerting profile is always created or updated before the email notification that depends on it β€” no depends_on required.


πŸ“₯ Inputs

Variable Type Required Default
name string Yes β€”
profile string Yes β€”
subject string Yes β€”
body string Yes β€”
to set(string) Yes β€”
cc set(string) No []
bcc set(string) No []
notify_closed_problems bool No null (argument omitted; defers to server-side behavior)
active bool No false (secure-by-default)
Full variable schemas (as declared in variables.tf)
  • name (string, required) β€” the name of the notification configuration. No documented provider default.
  • profile (string, required) β€” the ID of the associated Dynatrace alerting profile. Pass the id output of a terraform-dynatrace-alerting-profile instance; this module does not create or manage the profile itself.
  • subject (string, required) β€” the subject line of the email notifications. Supports Dynatrace notification placeholders ({ProblemTitle}, {ProblemID}, {ProblemSeverity}, {ProblemImpact}, {ImpactedEntity}, {State}, {ProblemURL}, among others).
  • body (string, required) β€” the template body of the email notifications. Supports a broader placeholder set than subject, including {ProblemDetailsHTML}, {ProblemDetailsJSONv2}, {ProblemDetailsMarkdown}, {ProblemDetailsText}, {Tags} / {Tags[key]}, and more.
  • to (set(string), required) β€” primary recipient email addresses. Raw provider schema type ["set", "string"] (TypeSet); order is not significant and duplicates are collapsed. Point these at organizational alerting distribution lists rather than individual personal inboxes.
  • cc (set(string), optional, default []) β€” additional (CC) recipient email addresses. Same TypeSet semantics as to.
  • bcc (set(string), optional, default []) β€” blind-carbon-copy recipient email addresses. Same TypeSet semantics as to.
  • notify_closed_problems (bool, optional, default null) β€” whether an email is also sent when a problem closes (true) or only when a problem opens (false). The provider documents no default for this field; leaving it null omits the argument entirely rather than guessing a value. Verify the resulting server-side behavior in a non-production environment before relying on it.
  • active (bool, optional, default false) β€” whether this configuration is enabled. Defaults to false per this module suite's secure-by-default standard for notification integrations, so a newly-applied integration does not fire before the caller reviews recipients, subject, body, and alerting profile scope.

🧾 Outputs

Output Description Sensitive
id The Dynatrace settings-object ID of this email notification configuration No
name The display name of this email notification configuration, as configured via var.name No

🧠 Architecture Notes

  • Flat, single-resource renderer. The live schema for dynatrace_email_notification has no nested block_types, so main.tf is a direct attribute-to-argument pass-through with no dynamic blocks and no try(x, null) wrapping needed beyond what the variable defaults already provide.
  • to/cc/bcc are sets, not lists. They mirror the provider's own TypeSet type. Order carries no meaning in either direction, and Terraform deduplicates entries within each field before they reach the API β€” do not build automation that depends on recipient ordering being preserved.
  • profile is a plain cross-module string reference. This module does not depends_on the alerting profile; wiring module.<alerting_profile>.id directly into profile (see Example 15) gives Terraform an implicit reference so the profile is always created or updated first.
  • active false is a module-level default, not a provider default. The provider leaves this field's behavior undocumented when entirely absent from the resource block; this module makes the choice explicit by rendering active = false unless the caller opts in.
  • notify_closed_problems left null is deliberate, not an oversight. Per house guidance for undocumented provider defaults, the module does not invent a plausible-sounding default β€” it omits the argument and defers to the Dynatrace API's own server-side behavior when unset.
  • No credential-bearing fields exist on this resource at all β€” unlike sibling notification-channel modules (Slack, webhook, PagerDuty, OpsGenie, ServiceNow, etc.), there is no sensitive = true variable in this module because there is no secret-shaped attribute in the underlying provider schema to protect.
  • No owned children, no for_each inside this module. Breadth at scale (multiple teams, environments, or channels) is achieved by the calling root module for_each-ing this module block itself, keyed by a caller-chosen map key β€” see Examples 12 and 13.

🧱 Design Principles

Concern Safe default Opt-out (caller must set explicitly)
Newly-applied notification integration active = false β€” the integration is created inert and cannot send email until reviewed Explicit active = true
Ambiguous open/close notification behavior notify_closed_problems = null β€” no invented default; the module does not guess the provider's undocumented server-side behavior Explicit true or false
CC/BCC recipient breadth cc/bcc default to [] β€” no additional recipients beyond to unless explicitly listed Populate cc/bcc explicitly
Primary recipients No default β€” to is required; a caller cannot apply this module without explicitly naming recipients N/A β€” required by the provider schema, not a module-level opt-out
Credential-bearing fields Not applicable β€” this resource has no sensitive fields; it is the one channel in this family without one N/A

πŸš€ Runbook

terraform init -backend=false
terraform validate
terraform fmt -check

Pin the module source to an explicit tag β€” ?ref=v1.0.0 β€” never a branch. This library is plan-only: a human applies from CI after reviewing the plan.


πŸ§ͺ Testing

terraform validate and terraform fmt -check prove the module's HCL is syntactically well-formed, that every required variable is supplied, that to/cc/bcc type-check as set(string) (rejecting a comma-joined string or a list literal with mismatched element types), and that the resource graph resolves. They do not prove that a given profile ID exists in the target environment, that the configured OAuth client or API token actually carries the settings.read/settings.write scopes, that Dynatrace accepts the literal email address strings supplied, or that subject/body placeholder syntax resolves the way the caller expects β€” those are only exercised by a real terraform plan/apply against a live Dynatrace environment, which this authoring process does not perform.


πŸ’¬ Example Output

$ terraform output

id = "vu9U3hXa3q0AAAAA"
name = "Email - Platform Team - Critical Availability"

πŸ” Troubleshooting

Symptom Cause Fix
apply fails with an authentication/authorization error The configured API token lacks settings.read/settings.write, or the OAuth client's IAM policy lacks settings:objects:read/settings:objects:write β€” or the wrong auth mechanism is configured at the provider level entirely Confirm the accepted mechanisms and scopes in Β§ Required OAuth Scopes / API Token Permissions above, and confirm the provider configuration itself (OAuth vs. platform token vs. API token)
apply succeeds but no email is ever sent active was left at its secure default of false Set active = true once recipients, subject, body, and alerting profile scope have been reviewed
plan fails because profile doesn't resolve The referenced alerting profile ID doesn't exist yet, or the wrong module's output was wired in Confirm the terraform-dynatrace-alerting-profile instance applies first, or reference its id output directly (Example 15) so Terraform orders the two implicitly
A cc/bcc address you added doesn't seem to show up, or order looks different than you typed it to/cc/bcc are TypeSets, not ordered lists; duplicates within a field are collapsed and element order isn't preserved Expect a deduplicated, unordered set; don't build downstream automation that depends on recipient order
Recipients get two copies of the same email The same address was listed in both to and cc (or cc and bcc) Deduplication only happens within a single field, not across to/cc/bcc β€” remove the address from all but one field
Open/close notification behavior seems inconsistent across environments notify_closed_problems was left at its null default, deferring to an undocumented server-side behavior Set notify_closed_problems explicitly to true or false for deterministic behavior
Subject or body renders a placeholder literally instead of substituting a value A placeholder name was typed incorrectly (e.g. {ProblemTile} instead of {ProblemTitle}) This module passes the string through unmodified β€” type { in the Dynatrace UI to get placeholder autocomplete, then copy the exact template into subject/body

πŸ”— Related Docs

  • Dynatrace provider resource reference: dynatrace_email_notification (dynatrace-oss/dynatrace, schemaId builtin:problem.notifications)
  • Sibling module: terraform-dynatrace-alerting-profile (owns the profile this module references)
  • Sibling notification-channel modules in this domain: terraform-dynatrace-slack-notification, terraform-dynatrace-webhook-notification, terraform-dynatrace-pagerduty-notification, terraform-dynatrace-ops-genie-notification, terraform-dynatrace-servicenow-notification, terraform-dynatrace-jira-notification, terraform-dynatrace-trello-notification, terraform-dynatrace-victorops-notification, terraform-dynatrace-xmatters-notification, terraform-dynatrace-ansible-tower-notification
  • This module's SCOPE.md

πŸ’™ "Infrastructure as Code should be standardized, consistent, and secure."

About

Terraform module: terraform-dynatrace-email-notification

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages