# Manage Email Addresses

Email addresses are a core component of the **Email SDK**. Addresses for different configured domains can be provisioned and used to communicate with other recipients.

Provisioning an email address is a two-step process. First, a check should be performed to determine if the email address is valid and available. Once results are returned and the desired address is selected, the address can be provisioned to a Sudo.

## Get Supported Email Domains

When provisioning a new email address for your user, a domain is needed to ensure the email address will be valid. The Sudo Platform email service can be configured to support issuing email addresses for multiple domains.

{% hint style="info" %}
Each project in your Sudo Platform account can be configured to support a set of email domains. Your solutions engineer can assist you in configuring DNS entries for domains you own or you can have the Sudo Platform do that on your behalf.
{% endhint %}

A call to the `getSupportedEmailDomains` method allows your user to perform a domain search in order to retrieve a list of supported domains for provisioning an email address.

{% tabs %}
{% tab title="TypeScript" %}

```typescript
try {
    const domains = await emailClient.getSupportedEmailDomains()
    // `domains` contains a list of supported domains to be used for email address provisioning.
} catch {
    // Handle/notify user of errors
}
```

{% endtab %}

{% tab title="Swift" %}

```swift
do {
    let domains = try await emailClient.getSupportedEmailDomains()
    /// `domains` contains a list of supported domains to be used for email address provisioning.
} catch {
    /// Handle/notify user of errors
}
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
launch {
    try {
        val domains = withContext(Dispatchers.IO) {
            emailClient.getSupportedEmailDomains()
        }
        // [domains] contains a list of supported domains to be used for email address provisioning.
    } catch (e: EmailAddressException) {
        // Handle/notify user of exception
    }
 }
```

{% endtab %}
{% endtabs %}

## Get Configured Email Domains

The Email SDK also provides a method to retrieve the configured email domains in your Sudo Platform account. This is used as part of email send operations to allows appropriate encryption decisions to be made when attempting to send end-to-end encrypted email messages.

A call to the `getConfiguredEmailDomains` method returns a list of these configured email domains.

{% tabs %}
{% tab title="TypeScript" %}

```typescript
try {
    const configuredDomains = await emailClient.getConfiguredEmailDomains(
        CachePolicy.RemoteOnly
    )
    // `configuredDomains` contains a list of configured domains.
} catch {
    // Handle/notify user of errors
}
```

{% endtab %}

{% tab title="Swift" %}

```swift
do {
    let configuredDomains = try await emailClient.getConfiguredEmailDomains()
    /// `configuredDomains` contains a list of configured domains.
} catch {
    /// Handle/notify user of errors
}
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
launch {
    try {
        val domains = withContext(Dispatchers.IO) {
            emailClient.getConfiguredEmailDomains()
        }
        // [configuredDomains] contains a list of configured domains.
    } catch (e: EmailAddressException) {
        // Handle/notify user of exception
    }
 }
```

{% endtab %}
{% endtabs %}

## Check Email Address Availability

When choosing a unique email address, it is important to give your user feedback as to whether the email address they are attempting to provision is valid or not. This is achieved by using the `checkEmailAddressAvailability` method.

The first input property, `localParts`, takes in a set of [local parts](https://en.wikipedia.org/wiki/Email_address#Local-part) to validate and check if they are available. If any of the local parts are invalid or the input contains more than five local parts to check, an invalid argument error will be returned.

The second input property, `domains`, should be a set of email domains exclusively supported by the email service. It is recommended to use the `getSupportedEmailDomains` method to retrieve this set. If an unsupported domain is supplied, an invalid email domain error will be returned.

{% tabs %}
{% tab title="TypeScript" %}

```typescript
try {
    const localParts = Set(['johndoe', 'jane.citizen'])
    const domains = await emailClient.getSupportedEmailDomains(
        CachePolicy.RemoteOnly
    )
    const emailAddresses = await emailClient.checkEmailAddressAvailability({
        localParts,
        domains,
    })
    // For example, if the domains list is:
    // [
    //    "example.com",
    //    "sudoplatform.com"
    // ]
    // And all emails are available for both domains, this would return a result 
    // that looks like this:
    // [
    //    "johndoe@example.com",
    //    "johndoe@sudoplatform.com",
    //    "jane.citizen@example.com",
    //    "jane.citizen@sudoplatform.com"
    // ]
} catch {
    // Handle/notify user of errors
}
```

{% endtab %}

{% tab title="Swift" %}

```swift
let localParts = ["johndoe", "jane.citizen"]
/// In reality, this would be a subset of the result of `getSupportedDomains`.
let supportedDomains = ["example.com", "sudoplatform.com"]
do {
    let checkAddressInput = CheckEmailAddressAvailabilityInput(
        localParts: [localPart],
        domains: [domain]
    )
    let validAddresses = try await emailClient.checkEmailAddressAvailability(
        withInput: checkAddressInput
    )
    /// If all emails were available for both domains, this would return a result that looks like this:
    /// [
    ///    "johndoe@example.com",
    ///    "johndoe@sudoplatform.com",
    ///    "jane.citizen@example.com",
    ///    "jane.citizen@sudoplatform.com"
    /// ]
} catch {
    /// Handle/notify user of error
}

```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
launch {
    try {
        val localParts = listOf("johndoe", "jane.citizen")
        val supportedDomains = emailClient.getSupportedEmailDomains()
        val input = CheckEmailAddressAvailabilityInput(
            localParts = localParts,
            domains = supportedDomains
        )
        val emailAddresses = emailClient.checkEmailAddressAvailability(input)
        // If all emails are available for both domains, 
        // this would return a result that looks like this:
        // [
        //    "johndoe@example.com",
        //    "johndoe@sudoplatform.com",
        //    "jane.citizen@example.com",
        //    "jane.citizen@sudoplatform.com"
        // ]
     } catch (e: EmailAddressException) {
        // Handle/notify user of error
     }
}
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
All email addresses will be lower-cased in the return result. For example a local part input of `JoHnDoE` would be returned as `johndoe...`.
{% endhint %}

## Provision Email Address

Once an available email address has been found, it can be used to provision a valid email address for a Sudo. An email address can be provisioned by calling the `provisionEmailAddress` method and will return the newly provisioned email address object.

{% hint style="warning" %}
The input email address must be valid and available, so it is highly recommended that you use the [Check Email Address Availability](#check-email-address-availability) API to validate the email address first.
{% endhint %}

An `ownershipProofToken` is required as part of the input. This ties together the Sudo and email address such that the Sudo becomes the owner of the email address. Use the `getOwnershipProof` method on the `SudoProfilesClient` in the **Sudo** **Profiles SDK** in order to obtain an `ownershipProofToken`. See the [Sudo](https://docs.sudoplatform.com/guides/sudos) section for more information.

An optional `alias` can also be provided as part of the input to provision an email address. The alias can be updated after initially provisioning the email address as discussed in the [Updating Metadata of an Email Address](#updating-metadata-of-an-email-address) section.

When an email address is provisioned, a set of standard email folders is also created and associated with the newly provisioned email address. Find out more about managing email folders [here](https://docs.sudoplatform.com/guides/email/manage-email-folders).

{% tabs %}
{% tab title="TypeScript" %}

```typescript
const emailAddressInput: string = // Found via the check email address availability API
const ownershipProofToken: string = // Found via the get ownership proof API (See "Sudos" section)
try {
    const emailAddress = await emailClient.provisionEmailAddress({
        emailAddressInput,
        ownershipProofToken,
        alias: 'John Smith' // Optionally supply an alias
    })
} catch {
    // Handle/notify user of errors 
}
```

{% endtab %}

{% tab title="Swift" %}

```swift

let emailAddress = self.input.emailAddress  /// String of the form "\(localPart)@\(domain)"
let ownershipProofToken = self.input.ownershipProofToken   /// Found via the get ownership proof API (See "Sudos" section)
do {
    let provisionAddressInput = ProvisionEmailAddressInput(
        emailAddress: emailAddress,
        ownershipProofToken: ownershipProofToken,
        alias: "Fred Smith"   /// optional alias for the provisioned email address
    )
    let provisionedEmailAddress = try await emailClient.provisionEmailAddress(
        withInput: provisionAddressInput
    )
    /// `provisionedEmailAddress` contains the newly provisioned email address.
} catch {
    /// Handle/notify user of error
}
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
val emailAddress: String = // Found via the check email address availability API
val ownershipProofToken: String = // Found via the getOwnershipProof API (See "Sudos" section)
launch {
    try {
        val input = ProvisionEmailAddressInput(
            emailAddress = emailAddress,
            ownershipProofToken = ownershipProofToken,
            alias = 'John Smith' // Optionally supply an alias
        )
        val emailAddress = withContext(Dispatchers.IO) {
            emailClient.provisionEmailAddress(input)
        }
        // The returned [emailAddress] has been provisioned
    } catch (e: EmailAddressException) {
        // Handle/notify user of exception
    }
 }
```

{% endtab %}
{% endtabs %}

### Entitlements

In order to be able to provision an email address, the user must be entitled. To provision an email address the following entitlement checks are performed:

1. The user must not have more Sudo Profiles than permitted by their `sudoplatform.sudo.max` entitlement.
2. The user is entitled to provision email addresses by the `sudoplatform.email.emailAddressUserEntitled` entitlement.
3. The Sudo Profile against which the new email address is to be provisioned has at least 1 remaining `sudoplatform.email.emailAddressMaxPerSudo` entitlement to consume.

If these entitlements' checks do not succeed, the `provisionEmailAddress` API fails with an insufficient entitlements error.

{% hint style="info" %}
See [Email Entitlements](https://docs.sudoplatform.com/guides/email/email-entitlements) for an overview of how the Email service integrates with the Sudo Platform Entitlements system.
{% endhint %}

## Deprovision Email Address

An email address can be deprovisioned using the `deprovisionEmailAddress` method by passing in the `id` of an existing email address object. The email address object that was deprovisioned will be returned and will no longer be usable for provisioning another email address.

{% hint style="warning" %}
By deprovisioning the email address, the user's address and all associated user data including messages and folders will be deleted; the email address will no longer be usable. The deprovisioned address will also be held indefinitely and be blocked for re-use from a subsequent provision call.
{% endhint %}

{% tabs %}
{% tab title="TypeScript" %}

```typescript
// Collect the input email address id however makes sense for your implementation.
const emailAddressId = emailAddress.id
try {
    const emailAddress = await emailClient.deprovisionEmailAddress(
        emailAddressId
    )
    // The returned `emailAddress` has now been deprovisioned.
} catch {
    // Handle/notify user of errors 
}
```

{% endtab %}

{% tab title="Swift" %}

```swift
/// Collect the input email address id however makes sense for your implementation.
let provisionedEmailAddressId = self.input.emailAddressId
do {
    let deprovisionedEmailAddress = try await emailClient.deprovisionEmailAddress(
        provisionedEmailAddressId
    )
    /// `deprovisionedEmailAddress` is the record that was just deprovisioned.
} catch {
    /// Handle/notify user of error
}
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
// Collect the input email address id however makes sense for your implementation.
val emailAddressId = emailAddress.id
launch {
    try {
        val emailAddress = withContext(Dispatchers.IO) {
            emailClient.deprovisionEmailAddress(emailAddressId)
        }
        // The returned [emailAddress] has now been deprovisioned.
    } catch (e: EmailAddressException) {
        // Handle/notify user of exception
    }
}
```

{% endtab %}
{% endtabs %}

## Updating Metadata of an Email Address

The metadata of an email address object can be updated by calling the `updateEmailAddressMetadata` method. Currently, the only attribute that can be updated on an email address object is the `alias`. The `alias` is an encrypted optional attribute on the email address object which can be modified by the user.

{% tabs %}
{% tab title="TypeScript" %}

```typescript
// Collect the input email address id however makes sense for your implementation.
try {
    const id = await emailClient.updateEmailAddressMetadata({
        id,
        values: { alias: 'John Smith' },
    })
    // `id` contains the identifier of the newly updated email address object.
} catch {
    // Handle/notify user of errors 
}
```

{% endtab %}

{% tab title="Swift" %}

```swift
/// Collect the input email address id however makes sense for your implementation.
let emailAddressId = input.emailAddress.id
let updateEmailAddressMetadataInput = UpdateEmailAddressMetadataInput(
    id: emailAddress.id,
    values: UpdateEmailAddressMetadataValues(alias: "newAlias")
)
do {
    let updatedEmailAddressId = try await client.updateEmailAddressMetadata(
        withInput: updateEmailAddressMetadataInput
    )
    /// `updatedEmailAddressId` contains the identifier of the newly updated email address object.
} catch {
    /// Handle/notify user of error
}
```

{% endtab %}

{% tab title="Kotlin" %}

<pre class="language-kotlin"><code class="lang-kotlin">/// Collect the input email address id however makes sense for your implementation.
<strong>val emailAddressId = emailAddress.id
</strong>launch {
    try {
        val input = UpdateEmailAddressMetadataInput(
            id = emailAddress.id,
            alias = "newAlias"
        )
        val updatedEmailAddressId = withContext(Dispatchers.IO) {
            emailClient.updateEmailAddressMetadata(input)
        }
        // The returned [updatedEmailAddressId] contains the identifier of the newly updated email address object.
    } catch (e: EmailAddressException) {
        // Handle/notify user of exception
    }
}
</code></pre>

{% endtab %}
{% endtabs %}

## Retrieving Existing Email Addresses

Previously provisioned email addresses can be accessed in two ways: via its identifier ([Single Email Address by Id](#using-email-address-id)), or via a broad multi access method ([Multiple Provisioned Email Addresses](#all-provisioned-email-addresses)).

{% hint style="warning" %}
If an email address has been provisioned and then deprovisioned, it will no longer be available via the methods discussed in this section.
{% endhint %}

A fetch of single or multiple email addresses can be performed remotely or locally by specifying the appropriate [CachePolicy](https://docs.sudoplatform.com/guides/email/caching-1) as part of the input.

### Single Email Address by Id

To retrieve a single email address given its unique `id`, use the `getEmailAddress` method. This method will return the record if it exists.

{% tabs %}
{% tab title="TypeScript" %}

```typescript
try {
    const emailAddress = await emailClient.getEmailAddress({
        id,
        cachePolicy: CachePolicy.RemoteOnly,
    })
    // `emailAddress` contains the email address object, else `undefined` if not found.
} catch {
    // Handle/notify user of errors
}
```

{% endtab %}

{% tab title="Swift" %}

```swift
/// Collect the input address of the email address object.
let emailAddressId = input.address.id
let getEmailAddressInput = GetEmailAddressInput(id: emailAddressId)
do {
    let emailAddress = try await emailClient.getEmailAddress(
        withInput: getEmailAddressInput
    )
    /// `emailAddress` contains the email address object, else `nil` if not found.
} catch {
    /// Handle/notify user of error
}
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
val emailAddressId = emailAddress.id
launch {
    try {
        val input = GetEmailAddressInput(
            id = emailAddressId
        )
        val emailAddress = withContext(Dispatchers.IO) {
            emailClient.getEmailAddress(input)
        }
        // [emailAddress] contains the email address object, else [null] if not found.
    } catch (e: EmailAddressException) {
        // Handle/notify user of exception
    }
}
```

{% endtab %}
{% endtabs %}

### Multiple Provisioned Email Addresses

The ability to retrieve multiple or all email addresses available to the user is supported. These results can be [paginated](https://docs.sudoplatform.com/guides/email/pagination).

A call to a list API will return a `ListEmailAddressesResult` with a `status` and depending on the status, a list of matching `items` and a `nextToken` to support pagination. If no results matching the input are found, the result will contain empty items. There can be three possible statuses returned:

| Status  | Definition                                                                                                                                                                                                                          |
| ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Success | A list of all requested email addresses are returned.                                                                                                                                                                               |
| Partial | A list of all email addresses that were successfully fetched and unencrypted are returned as well as a list of all email addresses that failed to unencrypt successfully, including an error indicating the reason for the failure. |
| Failure | All email addresses failed to be fetched or unencrypted. Contains an error indicating the reason for the failure.                                                                                                                   |

{% hint style="warning" %}
An email address may fail to be unencrypted if the version of the client is not up-to-date or if the required cryptographic key is missing from the client device.
{% endhint %}

#### All Provisioned Email Addresses

To retrieve multiple email addresses that are owned by the signed in user, call the `listEmailAddresses` method.

{% tabs %}
{% tab title="TypeScript" %}

```typescript
try {
    const result = await emailClient.listEmailAddresses({
        cachePolicy: CachePolicy.RemoteOnly,
        limit: 20,
        nextToken,
    })
    if (result.status === ListOperationResultStatus.Success) {
        // `result` contains the list of items matching the input.
        // Page through the results if result.nextToken != undefined. 
    }
} catch {
    // Handle/notify user of errors
}
```

{% endtab %}

{% tab title="Swift" %}

```swift
let listEmailAddressesInput = ListEmailAddressesInput(
    limit: 20,
    nextToken: nil
)
do {
    let output = try await emailClient.listEmailAddresses(
        withInput: input
    )
    /// `output` contains a `ListOutput` item of results matching the call.
    /// `output.items` contains an array of `EmailAddress`
} catch {
    /// Handle/notify user
}
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
launch {
    try {
        val input = ListEmailAddressesInput(
            limit = 20,
            nextToken = nextToken
        )
        val result = withContext(Dispatchers.IO) { 
            emailClient.listEmailAddresses(input)
        }
        when (result) {
            is ListAPIResult.Success -> {
                // [result.items] contains the list of items matching the input.
                // Page through the results if [output.nextToken] != null.
            }
            is ListAPIResult.Partial -> {
                // [result.items] contains the list of items matching the input that decrypted successfully.
                // [result.failed] contains the list of items that failed decryption with associated error.
                //  Page through the results if [partial.nextToken] != null.
            }
        }
    } catch (e: EmailAddressException) {
        // Handle/notify user of exception
    }
}
```

{% endtab %}
{% endtabs %}

**All Provisioned Email Addresses for a Sudo**

To retrieve multiple email addresses that are owned by a particular Sudo, call the `listEmailAddressesForSudoId` method by passing in the `id` of the Sudo to query.

{% tabs %}
{% tab title="TypeScript" %}

```typescript
// Collect the input sudo id however makes sense for your implementation.
const sudoId = sudo.id
try {
    const result = await emailClient.listEmailAddressesForSudoId({
        sudoId,
        cachePolicy: CachePolicy.RemoteOnly,
        limit: 20,
        nextToken,
    })
    if (result.status === ListOperationResultStatus.Success) {
        // `result` contains the list of items matching the input.
        // Page through the results if result.nextToken != undefined. 
    }
} catch {
    // Handle/notify user of errors
}
```

{% endtab %}

{% tab title="Swift" %}

```swift
/// Collect the input sudo id however makes sense for your implementation.
let sudoId = sudo.id
let listEmailAddressesForSudoIdInput = ListEmailAddressesForSudoIdInput(
    sudoId: sudoId,
    limit: 20,
    nextToken: nil
)
do {
    let output = try await emailClient.listEmailAddressesForSudoId(
        withInput: listEmailAddressesForSudoId
    )
    /// `output` contains a `ListOutput` item of results matching the call.
    /// `output.items` contains an array of `EmailAddress`
} catch {
    /// Handle/notify user
}
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
// Collect the input sudo id however makes sense for your implementation.
val sudoId = sudo.id
launch {
    try {
        val input = ListEmailAddressesForSudoIdInput(
            sudoId = sudoId,
            limit = 20,
            nextToken = nextToken
        )
        val result = withContext(Dispatchers.IO) { 
            emailClient.listEmailAddressesForSudoId(input)
        }
        when (result) {
            is ListAPIResult.Success -> {
                // [result.items] contains the list of items matching the input.
                // Page through the results if [output.nextToken] != null.
            }
            is ListAPIResult.Partial -> {
                // [result.items] contains the list of items matching the input that decrypted successfully.
                // [result.failed] contains the list of items that failed decryption with associated error.
                //  Page through the results if [partial.nextToken] != null.
            }
        }
    } catch (e: EmailAddressException) {
        // Handle/notify user of exception
    }
}
```

{% endtab %}
{% endtabs %}

{% hint style="success" %}
For the best performance depending on your use case, look up email addresses by Sudo.
{% endhint %}

{% hint style="info" %}
By default, list email addresses API have a limit of 1MB of data when no limit is supplied.&#x20;
{% endhint %}
