From 8254226255844e4fbccc813a31a3b8dd9d066a3c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jan-Otto=20Kr=C3=B6pke?= <mail@jkroepke.de>
Date: Sat, 22 Jun 2024 18:08:30 +0200
Subject: [PATCH] New Resource:
 `azurerm_communication_service_email_domain_association`
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Signed-off-by: Jan-Otto Kröpke <mail@jkroepke.de>
---
 ...rvice_email_domain_association_resource.go | 312 ++++++++++++++++++
 ..._email_domain_association_resource_test.go | 210 ++++++++++++
 .../services/communication/registration.go    |   1 +
 ...ice_email_domain_association.html.markdown |  50 +++
 4 files changed, 573 insertions(+)
 create mode 100644 internal/services/communication/communication_service_email_domain_association_resource.go
 create mode 100644 internal/services/communication/communication_service_email_domain_association_resource_test.go
 create mode 100644 website/docs/r/communication_service_email_domain_association.html.markdown

diff --git a/internal/services/communication/communication_service_email_domain_association_resource.go b/internal/services/communication/communication_service_email_domain_association_resource.go
new file mode 100644
index 0000000000000..435dbea85b1e7
--- /dev/null
+++ b/internal/services/communication/communication_service_email_domain_association_resource.go
@@ -0,0 +1,312 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package communication
+
+import (
+	"context"
+	"fmt"
+	"log"
+	"slices"
+	"time"
+
+	"github.com/hashicorp/go-azure-helpers/lang/pointer"
+	"github.com/hashicorp/go-azure-helpers/lang/response"
+	"github.com/hashicorp/go-azure-helpers/resourcemanager/commonids"
+	"github.com/hashicorp/go-azure-sdk/resource-manager/communication/2023-03-31/communicationservices"
+	"github.com/hashicorp/go-azure-sdk/resource-manager/communication/2023-03-31/domains"
+	"github.com/hashicorp/terraform-provider-azurerm/internal/locks"
+	"github.com/hashicorp/terraform-provider-azurerm/internal/sdk"
+	"github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk"
+)
+
+var _ sdk.Resource = CommunicationServiceEmailDomainAssociationResource{}
+
+type CommunicationServiceEmailDomainAssociationResource struct{}
+
+type CommunicationServiceEmailDomainAssociationResourceModel struct {
+	CommunicationServiceId string `tfschema:"communication_service_id"`
+	EMailServiceDomainId   string `tfschema:"email_service_domain_id"`
+}
+
+func (CommunicationServiceEmailDomainAssociationResource) Arguments() map[string]*pluginsdk.Schema {
+	return map[string]*pluginsdk.Schema{
+		"communication_service_id": {
+			Type:         pluginsdk.TypeString,
+			Required:     true,
+			ForceNew:     true,
+			ValidateFunc: communicationservices.ValidateCommunicationServiceID,
+		},
+		"email_service_domain_id": {
+			Type:         pluginsdk.TypeString,
+			Required:     true,
+			ForceNew:     true,
+			ValidateFunc: domains.ValidateDomainID,
+		},
+	}
+}
+
+func (CommunicationServiceEmailDomainAssociationResource) Attributes() map[string]*pluginsdk.Schema {
+	return map[string]*pluginsdk.Schema{}
+}
+
+func (CommunicationServiceEmailDomainAssociationResource) ModelObject() interface{} {
+	return &CommunicationServiceEmailDomainAssociationResourceModel{}
+}
+
+func (CommunicationServiceEmailDomainAssociationResource) ResourceType() string {
+	return "azurerm_communication_service_email_domain_association"
+}
+
+func (r CommunicationServiceEmailDomainAssociationResource) Create() sdk.ResourceFunc {
+	return sdk.ResourceFunc{
+		Timeout: 5 * time.Minute,
+		Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error {
+			client := metadata.Client.Communication.ServiceClient
+			domainClient := metadata.Client.Communication.DomainClient
+
+			var model CommunicationServiceEmailDomainAssociationResourceModel
+
+			if err := metadata.Decode(&model); err != nil {
+				return err
+			}
+
+			communicationServiceId, err := communicationservices.ParseCommunicationServiceID(model.CommunicationServiceId)
+			if err != nil {
+				return fmt.Errorf("parsing Communication Service ID: %w", err)
+			}
+
+			eMailServiceDomainId, err := domains.ParseDomainID(model.EMailServiceDomainId)
+			if err != nil {
+				return fmt.Errorf("parsing EMail Service Domain ID: %w", err)
+			}
+
+			locks.ByName(communicationServiceId.CommunicationServiceName, "azurerm_communication_service")
+			defer locks.UnlockByName(communicationServiceId.CommunicationServiceName, "azurerm_communication_service")
+
+			locks.ByName(eMailServiceDomainId.DomainName, "azurerm_email_communication_service_domain")
+			defer locks.UnlockByName(eMailServiceDomainId.DomainName, "azurerm_email_communication_service_domain")
+
+			existingEMailServiceDomain, err := domainClient.Get(ctx, *eMailServiceDomainId)
+			if err != nil && !response.WasNotFound(existingEMailServiceDomain.HttpResponse) {
+				return fmt.Errorf("checking for the presence of existing EMail Service Domain %q: %+v", model.EMailServiceDomainId, err)
+			}
+
+			if response.WasNotFound(existingEMailServiceDomain.HttpResponse) {
+				return fmt.Errorf("EMail Service Domain %q does not exsits", model.EMailServiceDomainId)
+			}
+
+			existingCommunicationService, err := client.Get(ctx, *communicationServiceId)
+			if err != nil && !response.WasNotFound(existingCommunicationService.HttpResponse) {
+				return fmt.Errorf("checking for the presence of existing Communication Service %q: %+v", model.CommunicationServiceId, err)
+			}
+
+			if response.WasNotFound(existingCommunicationService.HttpResponse) {
+				return fmt.Errorf("Communication Service %q does not exists", model.CommunicationServiceId)
+			}
+
+			if existingCommunicationService.Model == nil || existingCommunicationService.Model.Properties == nil {
+				return fmt.Errorf("model/properties for %s was nil", model.CommunicationServiceId)
+			}
+
+			domainList := existingCommunicationService.Model.Properties.LinkedDomains
+			if domainList == nil {
+				domainList = pointer.FromSliceOfStrings(make([]string, 0, 1))
+			}
+
+			if slices.Contains(*domainList, eMailServiceDomainId.ID()) {
+				return fmt.Errorf("EMail Service Domain %q is already associated with Communication Service %q", model.EMailServiceDomainId, model.CommunicationServiceId)
+			}
+
+			*domainList = append(*domainList, eMailServiceDomainId.ID())
+			existingCommunicationService.Model.Properties.LinkedDomains = domainList
+
+			input := communicationservices.CommunicationServiceResourceUpdate{
+				Properties: &communicationservices.CommunicationServiceUpdateProperties{
+					LinkedDomains: domainList,
+				},
+			}
+
+			if _, err := client.Update(ctx, *communicationServiceId, input); err != nil {
+				return fmt.Errorf("updating %s: %+v", *communicationServiceId, err)
+			}
+
+			id := commonids.NewCompositeResourceID(communicationServiceId, eMailServiceDomainId)
+			metadata.SetID(id)
+
+			return nil
+		},
+	}
+}
+
+func (CommunicationServiceEmailDomainAssociationResource) Read() sdk.ResourceFunc {
+	return sdk.ResourceFunc{
+		Timeout: 5 * time.Minute,
+		Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error {
+			client := metadata.Client.Communication.ServiceClient
+			domainClient := metadata.Client.Communication.DomainClient
+
+			id, err := commonids.ParseCompositeResourceID(metadata.ResourceData.Id(), &communicationservices.CommunicationServiceId{}, &domains.DomainId{})
+			if err != nil {
+				return err
+			}
+
+			state := CommunicationServiceEmailDomainAssociationResourceModel{}
+			state.CommunicationServiceId = id.First.ID()
+			state.EMailServiceDomainId = id.Second.ID()
+
+			communicationServiceId, err := communicationservices.ParseCommunicationServiceID(state.CommunicationServiceId)
+			if err != nil {
+				return fmt.Errorf("parsing Communication Service ID: %w", err)
+			}
+
+			eMailServiceDomainId, err := domains.ParseDomainID(state.EMailServiceDomainId)
+			if err != nil {
+				return fmt.Errorf("parsing EMail Service Domain ID: %w", err)
+			}
+
+			locks.ByName(communicationServiceId.CommunicationServiceName, "azurerm_communication_service")
+			defer locks.UnlockByName(communicationServiceId.CommunicationServiceName, "azurerm_communication_service")
+
+			locks.ByName(eMailServiceDomainId.DomainName, "azurerm_email_communication_service_domain")
+			defer locks.UnlockByName(eMailServiceDomainId.DomainName, "azurerm_email_communication_service_domain")
+
+			existingEMailServiceDomain, err := domainClient.Get(ctx, *eMailServiceDomainId)
+			if err != nil && !response.WasNotFound(existingEMailServiceDomain.HttpResponse) {
+				return fmt.Errorf("checking for the presence of existing EMail Service Domain %q: %+v", state.EMailServiceDomainId, err)
+			}
+
+			if response.WasNotFound(existingEMailServiceDomain.HttpResponse) {
+				return fmt.Errorf("EMail Service Domain %q does not exsits", state.EMailServiceDomainId)
+			}
+
+			existingCommunicationService, err := client.Get(ctx, *communicationServiceId)
+			if err != nil && !response.WasNotFound(existingCommunicationService.HttpResponse) {
+				return fmt.Errorf("checking for the presence of existing Communication Service %q: %+v", state.CommunicationServiceId, err)
+			}
+
+			if response.WasNotFound(existingCommunicationService.HttpResponse) {
+				return fmt.Errorf("Communication Service %q does not exsits", state.CommunicationServiceId)
+			}
+
+			if existingCommunicationService.Model == nil || existingCommunicationService.Model.Properties == nil {
+				return fmt.Errorf("model/properties for %s was nil", state.CommunicationServiceId)
+			}
+
+			domainList := existingCommunicationService.Model.Properties.LinkedDomains
+			if domainList == nil {
+				domainList = pointer.FromSliceOfStrings(make([]string, 0, 1))
+			}
+
+			if !slices.Contains(*domainList, eMailServiceDomainId.ID()) {
+				log.Printf("EMail Service Domain %q does not exsits in %q, removing from state.", eMailServiceDomainId, communicationServiceId)
+				err := metadata.MarkAsGone(id)
+				if err != nil {
+					return err
+				}
+			}
+
+			return metadata.Encode(&state)
+		},
+	}
+}
+
+func (CommunicationServiceEmailDomainAssociationResource) Delete() sdk.ResourceFunc {
+	return sdk.ResourceFunc{
+		Timeout: 5 * time.Minute,
+		Func: func(ctx context.Context, metadata sdk.ResourceMetaData) error {
+			client := metadata.Client.Communication.ServiceClient
+			domainClient := metadata.Client.Communication.DomainClient
+
+			var model CommunicationServiceEmailDomainAssociationResourceModel
+
+			if err := metadata.Decode(&model); err != nil {
+				return err
+			}
+
+			communicationServiceId, err := communicationservices.ParseCommunicationServiceID(model.CommunicationServiceId)
+			if err != nil {
+				return fmt.Errorf("parsing Communication Service ID: %w", err)
+			}
+
+			eMailServiceDomainId, err := domains.ParseDomainID(model.EMailServiceDomainId)
+			if err != nil {
+				return fmt.Errorf("parsing EMail Service Domain ID: %w", err)
+			}
+
+			locks.ByName(communicationServiceId.CommunicationServiceName, "azurerm_communication_service")
+			defer locks.UnlockByName(communicationServiceId.CommunicationServiceName, "azurerm_communication_service")
+
+			locks.ByName(eMailServiceDomainId.DomainName, "azurerm_email_communication_service_domain")
+			defer locks.UnlockByName(eMailServiceDomainId.DomainName, "azurerm_email_communication_service_domain")
+
+			existingEMailServiceDomain, err := domainClient.Get(ctx, *eMailServiceDomainId)
+			if err != nil && !response.WasNotFound(existingEMailServiceDomain.HttpResponse) {
+				return fmt.Errorf("checking for the presence of existing EMail Service Domain %q: %+v", model.EMailServiceDomainId, err)
+			}
+
+			if response.WasNotFound(existingEMailServiceDomain.HttpResponse) {
+				return fmt.Errorf("EMail Service Domain %q does not exsits", model.EMailServiceDomainId)
+			}
+
+			existingCommunicationService, err := client.Get(ctx, *communicationServiceId)
+			if err != nil && !response.WasNotFound(existingCommunicationService.HttpResponse) {
+				return fmt.Errorf("checking for the presence of existing Communication Service %q: %+v", model.CommunicationServiceId, err)
+			}
+
+			if response.WasNotFound(existingCommunicationService.HttpResponse) {
+				return fmt.Errorf("Communication Service %q does not exsits", model.CommunicationServiceId)
+			}
+
+			if existingCommunicationService.Model == nil || existingCommunicationService.Model.Properties == nil {
+				return fmt.Errorf("model/properties for %s was nil", model.CommunicationServiceId)
+			}
+
+			domainList := existingCommunicationService.Model.Properties.LinkedDomains
+			if domainList == nil {
+				domainList = pointer.FromSliceOfStrings(make([]string, 0, 1))
+			}
+
+			id := commonids.NewCompositeResourceID(communicationServiceId, eMailServiceDomainId)
+			metadata.SetID(id)
+
+			if !slices.Contains(*domainList, eMailServiceDomainId.ID()) {
+				return nil
+			}
+
+			*domainList = slices.DeleteFunc(*domainList, func(n string) bool {
+				return n == eMailServiceDomainId.ID()
+			})
+
+			existingCommunicationService.Model.Properties.LinkedDomains = domainList
+
+			input := communicationservices.CommunicationServiceResourceUpdate{
+				Properties: &communicationservices.CommunicationServiceUpdateProperties{
+					LinkedDomains: domainList,
+				},
+			}
+
+			if _, err := client.Update(ctx, *communicationServiceId, input); err != nil {
+				return fmt.Errorf("updating %s: %+v", *communicationServiceId, err)
+			}
+
+			return nil
+		},
+	}
+}
+
+func (CommunicationServiceEmailDomainAssociationResource) IDValidationFunc() pluginsdk.SchemaValidateFunc {
+	return func(input interface{}, key string) (warnings []string, errors []error) {
+		v, ok := input.(string)
+		if !ok {
+			errors = append(errors, fmt.Errorf("expected %q to be a string", key))
+			return
+		}
+
+		if _, err := commonids.ParseCompositeResourceID(v, &communicationservices.CommunicationServiceId{}, &domains.DomainId{}); err != nil {
+			errors = append(errors, err)
+		}
+
+		return
+	}
+}
diff --git a/internal/services/communication/communication_service_email_domain_association_resource_test.go b/internal/services/communication/communication_service_email_domain_association_resource_test.go
new file mode 100644
index 0000000000000..7f429d480284f
--- /dev/null
+++ b/internal/services/communication/communication_service_email_domain_association_resource_test.go
@@ -0,0 +1,210 @@
+// Copyright (c) HashiCorp, Inc.
+// SPDX-License-Identifier: MPL-2.0
+
+package communication_test
+
+import (
+	"context"
+	"fmt"
+	"slices"
+	"testing"
+	"time"
+
+	"github.com/hashicorp/go-azure-helpers/lang/response"
+	"github.com/hashicorp/go-azure-helpers/resourcemanager/commonids"
+	"github.com/hashicorp/go-azure-sdk/resource-manager/communication/2023-03-31/communicationservices"
+	"github.com/hashicorp/go-azure-sdk/resource-manager/communication/2023-03-31/domains"
+	"github.com/hashicorp/terraform-provider-azurerm/internal/acceptance"
+	"github.com/hashicorp/terraform-provider-azurerm/internal/acceptance/check"
+	"github.com/hashicorp/terraform-provider-azurerm/internal/clients"
+	"github.com/hashicorp/terraform-provider-azurerm/internal/tf/pluginsdk"
+)
+
+type CommunicationServiceEmailDomainAssociationResource struct{}
+
+func TestAccCommunicationServiceEmailDomainAssociationResource_basic(t *testing.T) {
+	data := acceptance.BuildTestData(t, "azurerm_communication_service_email_domain_association", "test")
+	r := CommunicationServiceEmailDomainAssociationResource{}
+	data.ResourceTest(t, r, []acceptance.TestStep{
+		{
+			Config: r.basic(data),
+			Check: acceptance.ComposeTestCheckFunc(
+				check.That(data.ResourceName).ExistsInAzure(r),
+			),
+		},
+		data.ImportStep(),
+	})
+}
+
+func TestAccCommunicationServiceEmailDomainAssociationResource_requiresImport(t *testing.T) {
+	data := acceptance.BuildTestData(t, "azurerm_communication_service_email_domain_association", "test")
+	r := CommunicationServiceEmailDomainAssociationResource{}
+	data.ResourceTest(t, r, []acceptance.TestStep{
+		{
+			Config: r.basic(data),
+			Check: acceptance.ComposeTestCheckFunc(
+				check.That(data.ResourceName).ExistsInAzure(r),
+			),
+		},
+		{
+			Config:      r.requiresImport(data),
+			ExpectError: acceptance.RequiresImportError("azurerm_communication_service_email_domain_association"),
+		},
+	})
+}
+
+func TestAccCommunicationServiceEmailDomainAssociationResource_deleted(t *testing.T) {
+	data := acceptance.BuildTestData(t, "azurerm_communication_service_email_domain_association", "test")
+	r := CommunicationServiceEmailDomainAssociationResource{}
+	data.ResourceTest(t, r, []acceptance.TestStep{
+		{
+			Config: r.basic(data),
+			Check: acceptance.ComposeTestCheckFunc(
+				check.That(data.ResourceName).ExistsInAzure(r),
+				data.CheckWithClient(r.destroy),
+			),
+			ExpectNonEmptyPlan: true,
+		},
+	})
+}
+
+func (r CommunicationServiceEmailDomainAssociationResource) Exists(ctx context.Context, client *clients.Client, state *pluginsdk.InstanceState) (*bool, error) {
+	exists := false
+
+	id, err := commonids.ParseCompositeResourceID(state.ID, &communicationservices.CommunicationServiceId{}, &domains.DomainId{})
+	if err != nil {
+		return &exists, fmt.Errorf("parsing ID: %w", err)
+	}
+
+	serviceClient := client.Communication.ServiceClient
+	existingCommunicationService, err := serviceClient.Get(ctx, *id.First)
+	if err != nil && !response.WasNotFound(existingCommunicationService.HttpResponse) {
+		return &exists, fmt.Errorf("checking for the presence of existing PrivateEndpoint %q: %+v", id.First, err)
+	}
+
+	if response.WasNotFound(existingCommunicationService.HttpResponse) {
+		return &exists, fmt.Errorf("PrivateEndpoint %q does not exsits", id.First)
+	}
+
+	input := existingCommunicationService
+	if input.Model != nil && input.Model.Properties != nil && input.Model.Properties.LinkedDomains != nil {
+		exists = slices.Contains(*input.Model.Properties.LinkedDomains, id.Second.ID())
+	}
+
+	return &exists, nil
+}
+
+func (r CommunicationServiceEmailDomainAssociationResource) basic(data acceptance.TestData) string {
+	return fmt.Sprintf(`
+%s
+
+resource "azurerm_communication_service_email_domain_association" "test" {
+  communication_service_id = azurerm_communication_service.test.id
+  email_service_domain_id  = azurerm_email_communication_service_domain.test.id
+}
+`, r.template(data))
+}
+
+func (r CommunicationServiceEmailDomainAssociationResource) template(data acceptance.TestData) string {
+	return fmt.Sprintf(`
+provider "azurerm" {
+  features {}
+}
+
+resource "azurerm_resource_group" "test" {
+  name     = "acctestRG-communicationservice-%[1]d"
+  location = "%[2]s"
+}
+
+resource "azurerm_communication_service" "test" {
+  name                = "acctest-CommunicationService-%[1]d"
+  resource_group_name = azurerm_resource_group.test.name
+  data_location       = "United States"
+
+  tags = {
+    env = "Test2"
+  }
+}
+
+resource "azurerm_email_communication_service" "test" {
+  name                = "acctest-CommunicationService-%[1]d"
+  resource_group_name = azurerm_resource_group.test.name
+  data_location       = "United States"
+}
+
+resource "azurerm_email_communication_service_domain" "test" {
+  name             = "AzureManagedDomain"
+  email_service_id = azurerm_email_communication_service.test.id
+
+  domain_management = "AzureManaged"
+}
+
+`, data.RandomInteger, data.Locations.Primary)
+}
+
+func (r CommunicationServiceEmailDomainAssociationResource) requiresImport(data acceptance.TestData) string {
+	return fmt.Sprintf(`
+%s
+
+resource "azurerm_communication_service_email_domain_association" "import" {
+  communication_service_id = azurerm_communication_service.test.id
+  email_service_domain_id  = azurerm_email_communication_service_domain.test.id
+}
+`, r.basic(data))
+}
+
+func (r CommunicationServiceEmailDomainAssociationResource) destroy(ctx context.Context, client *clients.Client, state *pluginsdk.InstanceState) error {
+	ctx, cancel := context.WithDeadline(ctx, time.Now().Add(15*time.Minute))
+	defer cancel()
+
+	communicationServiceId, err := communicationservices.ParseCommunicationServiceID(state.Attributes["communication_service_id"])
+	if err != nil {
+		return err
+	}
+
+	eMailServiceDomainId, err := domains.ParseDomainID(state.Attributes["email_service_domain_id"])
+	if err != nil {
+		return err
+	}
+
+	serviceClient := client.Communication.ServiceClient
+
+	existingCommunicationService, err := serviceClient.Get(ctx, *communicationServiceId)
+	if err != nil && !response.WasNotFound(existingCommunicationService.HttpResponse) {
+		return fmt.Errorf("checking for the presence of existing CommunicationService %q: %+v", communicationServiceId, err)
+	}
+
+	if response.WasNotFound(existingCommunicationService.HttpResponse) {
+		return fmt.Errorf("CommunicationService %q does not exsits", communicationServiceId)
+	}
+
+	if existingCommunicationService.Model == nil || existingCommunicationService.Model.Properties == nil || existingCommunicationService.Model.Properties.LinkedDomains == nil {
+		return fmt.Errorf("model/properties/application security groups was missing for %s", communicationServiceId)
+	}
+
+	// flag: application security group exists in private endpoint configuration
+	LinkedDomainInCommService := false
+
+	input := existingCommunicationService
+	LinkedDomainsList := *input.Model.Properties.LinkedDomains
+	newLinkedDomainsList := make([]string, 0)
+	for idx, value := range LinkedDomainsList {
+		if value == eMailServiceDomainId.ID() {
+			newLinkedDomainsList = append(newLinkedDomainsList, LinkedDomainsList[:idx]...)
+			newLinkedDomainsList = append(newLinkedDomainsList, LinkedDomainsList[idx+1:]...)
+			LinkedDomainInCommService = true
+			break
+		}
+	}
+	if LinkedDomainInCommService {
+		input.Model.Properties.LinkedDomains = &newLinkedDomainsList
+	} else {
+		return fmt.Errorf("deletion failed, EmailServiceDomain %q does not linked with CommunicationService %q", eMailServiceDomainId, communicationServiceId)
+	}
+
+	if err = serviceClient.CreateOrUpdateThenPoll(ctx, *communicationServiceId, *input.Model); err != nil {
+		return fmt.Errorf("creating %s: %+v", communicationServiceId, err)
+	}
+
+	return nil
+}
diff --git a/internal/services/communication/registration.go b/internal/services/communication/registration.go
index e5c2ba26e4977..0f58c62e4d2a7 100644
--- a/internal/services/communication/registration.go
+++ b/internal/services/communication/registration.go
@@ -37,6 +37,7 @@ func (r Registration) Resources() []sdk.Resource {
 	return []sdk.Resource{
 		EmailCommunicationServiceDomainResource{},
 		EmailCommunicationServiceResource{},
+		CommunicationServiceEmailDomainAssociationResource{},
 		CommunicationServiceResource{},
 	}
 }
diff --git a/website/docs/r/communication_service_email_domain_association.html.markdown b/website/docs/r/communication_service_email_domain_association.html.markdown
new file mode 100644
index 0000000000000..0c43419584532
--- /dev/null
+++ b/website/docs/r/communication_service_email_domain_association.html.markdown
@@ -0,0 +1,50 @@
+---
+subcategory: "Communication"
+layout: "azurerm"
+page_title: "Azure Resource Manager: azurerm_communication_service_email_domain_association"
+description: |-
+  Manages a communication service email domain association.
+---
+
+# azurerm_communication_service_email_domain_association
+
+Manages a communication service email domain association.
+
+## Example Usage
+
+```hcl
+resource "azurerm_communication_service_email_domain_association" "example" {
+  communication_service_id = "TODO"
+  email_service_domain_id = "TODO"
+}
+```
+
+## Arguments Reference
+
+The following arguments are supported:
+
+* `communication_service_id` - (Required) The ID of the Communication Service. Changing this forces a new communication service email domain association to be created.
+
+* `email_service_domain_id` - (Required) The ID of the EMail Service Domain. Changing this forces a new communication service email domain association to be created.
+
+## Attributes Reference
+
+In addition to the Arguments listed above - the following Attributes are exported: 
+
+* `id` - The ID of the communication service email domain association.
+
+## Timeouts
+
+The `timeouts` block allows you to specify [timeouts](https://www.terraform.io/language/resources/syntax#operation-timeouts) for certain actions:
+
+* `create` - (Defaults to 5 minutes) Used when creating the communication service email domain association.
+* `read` - (Defaults to 5 minutes) Used when retrieving the communication service email domain association.
+* `delete` - (Defaults to 5 minutes) Used when deleting the communication service email domain association.
+
+## Import
+
+Communication service email domain association can be imported using the `resource id`, e.g.
+
+```shell
+terraform import azurerm_communication_service_email_domain_association.example /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/group1/providers/Microsoft.Communication/communicationServices/communicationService1|/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/group1/providers/Microsoft.Communication/emailServices/emailCommunicationService1/domains/domain1
+```
\ No newline at end of file