Skip to content

Azure Communication Services

Overview

Azure Communication Services (ACS) provides cloud-based communication capabilities. This implementation adds support for sending transactional email through ACS by wiring together a Communication Service resource, an Email Communication Service, one or more sending domains, and sender usernames ("from" addresses).

The automation_variable_string module can consume these resources directly, so values like the ACS endpoint URL and email sender address are resolved at plan time rather than being written as plain strings in tfvars.

Module Structure

Module Azure Resource Purpose
communication_service azurerm_communication_service The ACS resource (endpoint, connection string)
email_communication_service azurerm_email_communication_service Email sending capability tied to a region
email_communication_service_domain azurerm_email_communication_service_domain Sending domain (Azure-managed or customer-managed)
email_communication_service_domain_sender_username azurerm_email_communication_service_domain_sender_username A specific "from" address on a domain
communication_service_email_domain_association azurerm_communication_service_email_domain_association Links a Communication Service to an Email Service Domain

Resource Relationships

email_communication_service
  └── email_communication_service_domain ◄── communication_service_email_domain_association ◄── communication_service
        └── email_communication_service_domain_sender_username

All five resources must be created for end-to-end email sending from ACS. The association is what allows the Communication Service to use the Email domain.

Usage

1. Create a Communication Service

communication_service = {
  patch-automation-communication-service = {
    resource_group = "hsw"
    data_location  = "United States"
    tags = {
      purpose = "patch-automation"
    }
  }
}

2. Create an Email Communication Service

email_communication_service = {
  patch-automation-email-service = {
    resource_group = "hsw"
    data_location  = "United States"
    tags = {
      purpose = "patch-automation"
    }
  }
}

3. Create an Email Domain

For an Azure-managed domain (Microsoft handles DNS/verification, name is always AzureManagedDomain):

email_communication_service_domain = {
  patch_automation_email_domain = {
    email_service     = "patch-automation-email-service"
    domain_management = "AzureManaged"
    tags = {
      purpose = "patch-automation"
    }
  }
}

For a customer-managed domain (you own the DNS zone):

email_communication_service_domain = {
  alerts_domain = {
    email_service     = "patch-automation-email-service"
    domain_management = "CustomerManaged"
    name              = "alerts.example.com"  # Required: actual DNS FQDN you own and will verify
  }
}

4. Create a Sender Username

email_communication_service_domain_sender_username = {
  patch_automation_email_domain_sender_username = {
    email_domain = "patch_automation_email_domain"
    name         = "ECSA_Alerts"
    display_name = "ECSA Alerts"
  }
}

The name becomes the left-hand side of the email address: ECSA_Alerts@<domain>.

5. Associate the Communication Service to the Email Domain

communication_service_email_domain_association = {
  patch_automation_email_domain_association = {
    communication_service = "patch-automation-communication-service"
    email_domain          = "patch_automation_email_domain"
  }
}

6. Reference from Automation Variable Strings

Rather than hardcoding ACS endpoint URLs or full email addresses in tfvars, use the built-in helpers on automation_variable_string:

automation_variable_string = {
  ACS_Endpoint = {
    automation_account = "sapphireautomationdev"
    name               = "ACS_Endpoint"
    acs_endpoint_from  = "patch-automation-communication-service"
    # Resolves to: https://<hostname> of the communication service
  }

  EmailSenderAddress = {
    automation_account = "sapphireautomationdev"
    name               = "EmailSenderAddress"
    email_sender_address_from = {
      sender_username = "patch_automation_email_domain_sender_username"
      email_domain    = "patch_automation_email_domain"
    }
    # Resolves to: ECSA_Alerts@<from_sender_domain>
  }
}

Variable Reference

communication_service

Field Type Description Default
name string Override the resource name Prefix + key + suffix
resource_group string Resource group key Required
data_location string Data residency region (e.g. "United States") Required
tags map(string) Resource tags {}

email_communication_service

Field Type Description Default
name string Override the resource name Prefix + key + suffix
resource_group string Resource group key Required
data_location string Data residency region Required
tags map(string) Resource tags {}

email_communication_service_domain

Field Type Description Default
name string Domain name. Required for CustomerManaged — must be the actual DNS FQDN (e.g. alerts.example.com). Omit for AzureManaged — Azure always names it AzureManagedDomain. null
email_service string email_communication_service key Required
domain_management string "AzureManaged" or "CustomerManaged" "AzureManaged"
user_engagement_tracking_enabled bool Append tracking pixels/links to sent email false
tags map(string) Resource tags {}

Customer-managed domains require name:

Azure rejects generated resource-style names for CustomerManaged domains. The name field must be set to the DNS domain you own and have the abiliity to verify (e.g. SapphireHealth.org). A Terraform validation enforces this at validate/plan time.

email_communication_service_domain_sender_username

Field Type Description Default
name string Sender username (appears left of @ in the from address) Prefix + key + suffix
email_domain string email_communication_service_domain key Required
display_name string Human-readable display name for the from address null

communication_service_email_domain_association

Field Type Description Default
communication_service string communication_service key Required
email_domain string email_communication_service_domain key Required

Naming Convention

Resources follow the standard {prefix}{key}{suffix} pattern. Add entries to your name_prefixes and name_suffixes in tfvars:

name_prefixes = {
  communication_service                              = "prod-"
  email_communication_service                        = "prod-"
  email_communication_service_domain                 = "prod-"
  email_communication_service_domain_sender_username = "prod-"
}

name_suffixes = {
  communication_service                              = "-acs"
  email_communication_service                        = "-ecs"
  email_communication_service_domain                 = "-ecsd"
  email_communication_service_domain_sender_username = "-ecsdsu"
}

Exception: communication_service_email_domain_association has no name (the Azure resource is identified by its two referenced IDs), so no prefix/suffix entries are needed for it.

Exception: Azure-managed domains always receive the name "AzureManagedDomain" regardless of prefix/suffix configuration.