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.