# Sending & Receiving Email

## Sending Email Messages

The **Email SDK** can handle sending email messages. Sending messages requires a provisioned email address as discussed in [Manage Email Addresses](https://docs.sudoplatform.com/guides/manage-email-addresses#provision-email-address).&#x20;

{% hint style="info" %}
We support using a raw [RFC 822](https://tools.ietf.org/html/rfc822) payload to allow flexible email composition within your application.
{% endhint %}

The `sendEmailMessage` method is used to send an email message. The first input property, `emailMessageHeader`, contains header fields such as `from`, `to`, `cc`, `bcc`, `replyTo` and `subject` which adhere to the RFC 822 standard. Further input properties include the message `body`, `attachments` and `inlineAttachments.` The last input property, `senderEmailAddressId`, must match the `id` of the email address from the `from` field in the header input. A call to this method returns the `id` and `created` timestamp of the sent email message to allow for a client to sync data from a remote source.

### Email Message End-to-end Encryption

When sending an email to in-network addresses (i.e. recipients with a provisioned email address within the Sudo Platform), the email message will be end-to-end encrypted. When sending an email to out-of-network addresses (i.e. recipients that do not have a registered email address against the Sudo Platform) the email message will not be end-to-end encrypted.&#x20;

{% hint style="warning" %}
Sending an email to a mixture of in-network and out-of-network recipients in a single email message will not be end-to-end encrypted.
{% endhint %}

End-to-end encrypted email messages contain attachments which hold the encrypted RFC 822 data and the cryptographic keys used to decrypt the message. These attachments are identifed based on the properties in the following table:

<table><thead><tr><th width="195"></th><th width="157">fileName</th><th width="187">mimeType</th><th>contentId</th></tr></thead><tbody><tr><td><strong>Key Attachment/s</strong></td><td>"Secure Data <em>n</em>"</td><td>"application/x-sudoplatform-key"</td><td>"securekeyexchangedata@sudoplatform.com"</td></tr><tr><td><strong>Body Attachment</strong></td><td>"Secure Email"</td><td>"application/x-sudoplatform-body"</td><td>"securebody@sudoplatform.com"</td></tr></tbody></table>

{% hint style="danger" %}
A single email message can be sent to a maximum of 20 recipients at once by default. Adding recipients to the email message which exceed this limit will throw a `LimitExceededError`.
{% endhint %}

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

```typescript
// Collect the input headers, body, attachments and sender email address id 
// however makes sense for your implementation.
const senderEmailAddressId: string = // ...
const emailMessageHeader: InternetMessageFormatHeader = {
    from: { emailAddress: "from@bar.com" },
    to: [{ emailAddress: "to@bar.com" }],
    cc: [{ emailAddress: "cc@bar.com" }],
    bcc: [{ emailAddress: "bcc@bar.com" }],
    replyTo: [{ emailAddress: "replyTo@bar.com" }],
    subject: "Example subject line",
}
const emailAttachment: EmailAttachment = {
    filename: "fooAttachment.pdf",
    contentId: uuid.v4(),
    mimeType: "application/pdf",
    inlineAttachment: false,
    data: // ... Some pdf data
}
const inlineAttachment: EmailAttachment = {
    filename: "fooImage.png",
    contentId: uuid.v4(),
    mimeType: "image/png",
    inlineAttachment: true,
    data: // ... Some image data
}
try {
    const input: SendEmailMessageInput = {
        senderEmailAddressId: senderEmailAddressId,
        emailMessageHeaders: emailMessageHeader,
        body: "An example email body",
        attachments: [emailAttachment],
        inlineAttachments: [inlineAttachment],
    }
    const result = await emailClient.sendEmailMessage(input)
    // `result` contains the identifier and created timestamp associated with the sent email message. You can use this to access the data of the email message.
} catch {
    // Handle/notify user of error 
}
```

{% endtab %}

{% tab title="Swift" %}

```swift
/// Collect the input headers, body, attachments and sender email address id 
/// however makes sense for your implementation.
let senderEmailAddressId: String = // ...
let emailMessageHeader = InternetMessageFormatHeader(
    from: EmailAddressDetail(emailAddress: "from@bar.com"),
    to: [EmailAddressDetail(emailAddress: "to@bar.com")],
    cc: [EmailAddressDetail(emailAddress: "cc@bar.com")],
    bcc: [EmailAddressDetail(emailAddress: "bcc@bar.com")],
    replyTo: [EmailAddressDetail(emailAddress: "replyTo@bar.com")],
    subject: "Example subject line"
)
let emailAttachment = EmailAttachment(
    filename: "fooAttachment.pdf",
    contentId: UUID().uuidString,
    mimetype: "application/pdf",
    inlineAttachment: false,
    data: // ... Some pdf data
)
let inlineAttachment = EmailAttachment(
    filename: "fooImage.png",
    contentId: UUID().uuidString,
    mimetype: "image/png",
    inlineAttachment: true,
    data: // ... Some image data
)
do {
    let input = SendEmailMessageInput(
        senderEmailAddressId: senderEmailAddressId,
        emailMessageHeaders: emailMessageHeader,
        body: "An example email body",
        attachments: [emailAttachment],
        inlineAttachments: [inlineAttachment]
    )
    let result = try await emailClient.sendEmailMessage(
        withInput: input
    )
    /// `result` contains the identifier and created timestamp associated with the sent email message. You can use this to access the data of the email message.
} catch {
    /// Handle/notify user of error
}
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
// Collect the input headers, body, attachments and sender email address id 
// however makes sense for your implementation.
val senderEmailAddressId: String = // ...
val emailMessageHeader = InternetMessageFormatHeader(
    from = EmailMessage.EmailAddress("from@bar.com"),
    to = listOf(EmailMessage.EmailAddress("to@bar.com")),
    cc = listOf(EmailMessage.EmailAddress("cc@bar.com")),
    bcc = listOf(EmailMessage.EmailAddress("bcc@bar.com")),
    replyTo = listOf(EmailMessage.EmailAddress("replyTo@bar.com")),
    subject = "Example subject line",
)
val emailAttachment = EmailAttachment(
    fileName = "fooAttachment.pdf",
    contentId = UUID.randomUUID().toString(),
    mimeType = "application/pdf",
    inlineAttachment = false,
    data = // ... Some pdf data
)
val inlineAttachment = EmailAttachment(
    fileName = "fooImage.png",
    contentId = UUID.randomUUID().toString(),
    mimeType = "image/png",
    inlineAttachment = true,
    data = // ... Some image data
)
launch {
    try {
        val input = SendEmailMessageInput(
            senderEmailAddressId = senderEmailAddressId,
            emailMessageHeaders = emailMessageHeader,
            body = "An example email body",
            attachments = listOf(emailAttachment),
            inlineAttachments = listOf(inlineAttachment),
        )
        val result = withContext(Dispatchers.IO) {
            emailClient.sendEmailMessage(input)
        }
        // [result] contains the identifier and created timestamp associated with the sent email message. You can use this to access the data of the email message.
    } catch (e: EmailMessageException) {
        // Handle/notify user of exception
    }
}
```

{% endtab %}
{% endtabs %}

### Entitlements

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

1. The user must be entitled to send emails by the`sudoplatform.email.emailMessageSendUserEntitled` entitlement.
2. The email address the user is sending from must have sufficient storage capacity available as determined by the `sudoplatform.email.emailStorageMaxPerEmailAddress` entitlement.

If these entitlements' checks do not succeed, the `sendEmailMessage` 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 %}

## Receiving Email Messages

Email messages can be received via subscribing to email message events or through polling on the email message retrieval APIs. See the [Subscribing to Email Message Events](#subscribing-to-email-message-events) section for information on the subscription method and see the [Retrieving Email Messages](#retrieving-email-messages) section for information on the polling method.

### Entitlements

While previously received emails are always able to be retrieved, in order to be able to receive new emails, the user must be entitled. To receive an email the following entitlement checks are performed:

1. The user must be entitled to receive emails by the`sudoplatform.email.emailMessageReceiveUserEntitled` entitlement.
2. The email address the email is addressed to must have sufficient storage capacity available as determined by the `sudoplatform.email.emailStorageMaxPerEmailAddress` entitlement.

If these entitlements checks do not succeed, the incoming email is rejected with a reason indicating that the storage quota has been exceeded allowing the sending email service to retry.

{% 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 %}

## Retrieving Email Messages

Sent and received email messages can be accessed in two ways: via its identifier ([Single Email Message by Id](#single-email-message-by-id)), or via a multi access method ([Multiple Email Messages](#multi-access-messages)).

{% hint style="info" %}
These retrieval methods return the email message metadata but not the content of the message. Email message metadata consists of the information such as: addressees, sender, subject, folder, timestamps, direction, whether or not it has attachments.&#x20;

To learn how to access the RFC 822 message content of the email message, see [Accessing RFC 822 Message Data](#accessing-rfc-822-message-data).
{% endhint %}

{% hint style="warning" %}
If an email message has been deleted, it will no longer be available for access.
{% endhint %}

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

### Single Email Message by Id

A single email message can be retrieved via its `id` using the `getEmailMessage` method. The `id` is typically returned from successfully [sending an email message](#sending-email). This method will return the record if it exists.

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

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

{% endtab %}

{% tab title="Swift" %}

```swift
/// Collect the input id of the email message object.
let input = GetEmailMessageInput(id: input.messageId)
do {
    let emailMessage = try await emailClient.getEmailMessage(
        withInput: input
    )
    // `emailMessage` contains the email message object, else `nil` if not found.
} catch {
    // Handle/notify user of errors
}
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
val emailMessageId = emailMessage.id
launch {
    try {
        val input = GetEmailMessageInput(
            id = emailMessageId
        )
        val emailMessage = withContext(Dispatchers.IO) {
            emailClient.getEmailMessage(input)
        }
        // [emailMessage] contains the email message object, else [null] if not found.
    } catch (e: EmailMessageException) {
        // Handle/notify user of exception
    }
}
```

{% endtab %}
{% endtabs %}

### Multiple Email Messages

The ability to retrieve multiple email messages 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 `ListEmailMessagesResult` 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 messages are returned.                                                                                                                                                                              |
| Partial | A list of all email messages that were successfully fetched and unencrypted are returned as well as a list of all email messages that failed to unencrypt successfully, including an error indicating the reason for the failure. |
| Failure | All email messages failed to be fetched or unencrypted. Contains an error indicating the reason for the failure.                                                                                                                  |

{% hint style="warning" %}
An email message 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 %}

An optional `dateRange` can also be supplied as part of the input to organise results. For listing email messages, the `sortDate` or `updatedAt` timestamps can be specified in order to perform the date range query on. The `sortDate` refers to the time in which an email message is sent or received. The `updatedAt` date refers to the time in which the email message was last updated. This could be due to a change in the message's seen status or the folder that it is assigned to.

{% hint style="warning" %}
Note that both timestamps cannot be specified, otherwise an `InvalidArgument` error will occur.
{% endhint %}

#### All Email Messages

To retrieve multiple email messages that are owned by the signed in user, call the `listEmailMessages` method.&#x20;

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

```typescript
const dateRange: EmailMessageDateRange = {
    updatedAt: {
        startDate: // startDate as a `Date` object
        endDate: // endDate as a `Date` object
    }
}
try {
    const result = await emailClient.listEmailMessages({
        dateRange,
        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 dateRange = EmailMessageDateRange(
    updatedAt: DateRange(
        startDate: // startDate as a `Date` object
        endDate: // endDate as a `Date` object
    )
)
let input = ListEmailMessagesInput(
    dateRange: dateRange,
    sortOrder: .asc,
    limit: 10,
    nextToken: nil
)
do {
    let result = try await emailClient.listEmailMessages(
        withInput: input
    )
    switch result {
    case .success(let successResult):
        // successResult.items contains an array of the email messages for the user.
        // successResult.nextToken will not be `nil` if there are more email messages to retrieve.
    case .partial(let partialResult):
        // partialResult.items contains an array of the email messages successfully 
        //  retrieved and unsealed for this user.
        // partialResult.failed contains an array of email messages retrieved 
        //  for this user, but unsuccessfully unsealed.
        // partialResult.nextToken will not be `nil` if there are more email messages to retrieve
    }
} catch {
    // Handle/notify user of errors
}
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
val dateRange = EmailMessageDateRange(
    updatedAt = DateRange(
        startDate = // startDate as a [Date]
        endDate = // endDate as a [Date]
    )
)
launch {
    try {
        val input = ListEmailMessagesInput(
            dateRange = dateRange,
            sortOrder = SortOrder.DESC,
            limit = 20,
            nextToken = nextToken
        )
        val result = withContext(Dispatchers.IO) { 
            emailClient.listEmailMessages(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: EmailMessageException) {
        // Handle/notify user of exception
    }
}
```

{% endtab %}
{% endtabs %}

#### All Email Messages for an Email Address

To retrieve multiple email messages that are assigned to a certain email address, call the `listEmailAddressesForEmailAddressId` method by passing in the `id` of the email address to query.

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

<pre class="language-typescript"><code class="lang-typescript"><strong>// Collect the input email address id however makes sense for your implementation.
</strong>const emailAddressId = emailAddress.id
const dateRange: EmailMessageDateRange = {
    updatedAt: {
        startDate: // startDate as a `Date` object
        endDate: // endDate as a `Date` object
    }
}
try {
    const result = await emailClient.listEmailMessagesForEmailAddressId({
        emailAddressId,
        dateRange,
        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
}
</code></pre>

{% endtab %}

{% tab title="Swift" %}

```swift
// Collect the input email address id however makes sense for your implementation.
let emailAddressId = emailAddress.id
let dateRange = EmailMessageDateRange(
    updatedAt: DateRange(
        startDate: // startDate as a `Date` object
        endDate: // endDate as a `Date` object
    )
)
let input = ListEmailMessagesForEmailAddressInput(
    emailAddressId: emailAddressId,
    dateRange: dateRange,
    sortOrder: .asc,
    limit: 10,
    nextToken: nil
)
do {
    let result = try await emailClient.listEmailMessagesForEmailAddressId(
        withInput: input
    )
    switch result {
    case .success(let successResult):
        // successResult.items contains an array of the email messages for this email address.
        // successResult.nextToken will not be `nil` if there are more email messages to retrieve.
    case .partial(let partialResult):
        // partialResult.items contains an array of the email messages successfully 
        //  retrieved and unsealed for this email address.
        // partialResult.failed contains an array of email messages retrieved 
        //  for this email address, but unsuccessfully unsealed.
        // partialResult.nextToken will not be `nil` if there are more email messages to retrieve
    }
} catch {
    // Handle/notify user of errors
}
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
// Collect the input email address id however makes sense for your implementation.
val emailAddressId = emailAddress.id
val dateRange = EmailMessageDateRange(
    updatedAt = DateRange(
        startDate = // startDate as a [Date]
        endDate = // endDate as a [Date]
    )
)
launch {
    try {
        val input = ListEmailMessagesForEmailAddressIdInput(
            emailAddressId = emailAddressId,
            dateRange = dateRange,
            sortOrder = SortOrder.DESC,
            limit = 20,
            nextToken = nextToken
        )
        val result = withContext(Dispatchers.IO) { 
            emailClient.listEmailMessagesForEmailAddressId(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: EmailMessageException) {
        // Handle/notify user of exception
    }
}
```

{% endtab %}
{% endtabs %}

#### All Email Messages for an Email Folder

To retrieve multiple email messages that are assigned to a certain email folder (i.e. Trash), call the `listEmailAddressesForEmailFolderId` method by passing in the `id` of the email folder to query.

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

```typescript
// Collect the input email folder id however makes sense for your implementation.
const emailFolderId = emailFolder.id
const dateRange: EmailMessageDateRange = {
    updatedAt: {
        startDate: // startDate as a `Date` object
        endDate: // endDate as a `Date` object
    }
}
try {
    const result = await emailClient.listEmailMessagesForEmailFolderId({
        emailFolderId,
        dateRange,
        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 email folder id however makes sense for your implementation.
let emailFolderId = emailFolder.id
let dateRange = EmailMessageDateRange(
    updatedAt: DateRange(
        startDate: // startDate as a `Date` object
        endDate: // endDate as a `Date` object
    )
)
let input = ListEmailMessagesForEmailFolderIdInput(
    emailFolderId: emailFolderId,
    dateRange: dateRange,
    sortOrder: .asc,
    limit: 10,
    nextToken: nil
)
do {
    let result = try await emailClient.listEmailMessagesForEmailFolderId(
        withInput: input
    )
    switch result {
    case .success(let successResult):
        // successResult.items contains an array of the email messages for this email folder.
        // successResult.nextToken will not be `nil` if there are more email messages to retrieve.
    case .partial(let partialResult):
        // partialResult.items contains an array of the email messages successfully 
        //  retrieved and unsealed for this email folder.
        // partialResult.failed contains an array of email messages retrieved 
        //  for this email folder, but unsuccessfully unsealed.
        // partialResult.nextToken will not be `nil` if there are more email messages to retrieve
    }
} catch {
    // Handle/notify user of errors
}
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
// Collect the input email folder id however makes sense for your implementation.
val emailFolderId = emailFolder.id
val dateRange = EmailMessageDateRange(
    updatedAt = DateRange(
        startDate = // startDate as a [Date]
        endDate = // endDate as a [Date]
    )
)
launch {
    try {
        val input = ListEmailMessagesForEmailFolderIdInput(
            folderId = emailFolderId,
            dateRange = dateRange,
            sortOrder = SortOrder.DESC,
            limit = 20,
            nextToken = nextToken
        )
        val result = withContext(Dispatchers.IO) { 
            emailClient.listEmailMessagesForEmailFolderId(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: EmailMessageException) {
        // Handle/notify user of exception
    }
}
```

{% endtab %}
{% endtabs %}

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

### Accessing RFC 822 Message Data

The **Email SDK** allows developers to interact with raw email data. The SDK's interfaces and documentation refer to this type of data as [RFC 822](https://tools.ietf.org/html/rfc822) data. While there are a number of internet standards, such as [RFC 2822](https://tools.ietf.org/html/rfc2822), [RFC 5322](https://tools.ietf.org/html/rfc5322) and [RFC 6854](https://datatracker.ietf.org/doc/html/rfc6854), that supersede the RFC 822 specification, the intent is that raw email data conforms to any of these specifications and is appropriate and interoperable with Sudo Platform emails.

To access the message body and headers of the email message, the RFC 822 data will need to be retrieved using the `getEmailMessageRfc822Data` method. The `id` of the email message is required to be passed into this method to access the data. The other methods previously supplied on this page only access the metadata of the email message.

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

```typescript
try {
    const rfc822Data = await emailClient.getEmailMessageRfc822Data({
        id,
        cachePolicy = CachePolicy.REMOTE_ONLY
    })
    // If the `id` matches an email message, `rfc822Data` will be returned, else `undefined` is returned.
    if (rfc822Data) {
        const emailMessageWithBody = // parse the `rfc822Data`
    }
} catch {
    // Handle/notify user of error 
}
```

{% endtab %}

{% tab title="Swift" %}

<pre class="language-swift"><code class="lang-swift"><strong>// Collect the input email message and email address ids however makes sense for your implementation.
</strong>let emailMessageId = emailMessage.id
let emailAddressId = emailAddress.id
let input = GetEmailMessageRfc822DataInput(
    id: emailMessageId,
    emailAddressId: emailAddressId
)
do {
    let rfc822Data = try await emailClient.getEmailMessageRfc822Data(
        withInput: input
    )
    // rfc822Data contains the raw RFC 6854 (supersedes RFC 822) data of 
    //  an email message associated with the `emailMessageId`.
} catch {
    // Handle/notify user of error 
}
</code></pre>

{% endtab %}

{% tab title="Kotlin" %}

<pre class="language-kotlin"><code class="lang-kotlin">// Collect the input email message and email address ids however makes sense for your implementation.
<strong>val emailMessageId = emailMessage.id
</strong>val emailAddressId = emailAddress.id
launch {
    try {
        val input = GetEmailMessageRfc822Data(
            id = emailMessageId,
            emailAddressId = emailAddressId
        )
        val rfc822Data = withContext(Dispatchers.IO) {
            emailClient.getEmailMessageRfc822Data(input)
        }
        // If the [id] matches an email message, [rfc822Data] will be returned, else [null]
        if (rfc822Data != null) {
             val emailMessageWithBody = // parse the [rfc822Data]
        }
    } catch (e: EmailMessageException) {
        // Handle/notify user of exception
    }
}
</code></pre>

{% endtab %}
{% endtabs %}

### Retrieve Email Message with Body

To retrieve and access the contents of an email message body, attachments and headers, call the `getEmailMessageWithBody` method. The `id` of the email message and the `id` of the associated email address is required to be passed in as input to access the message data. The other methods previously supplied on this page only access the metadata of the email message.

End-to-end encrypted email messages are decrypted using the attached cryptographic keys belonging to each recipient as specified in the table in the [Sending Email Messages](#sending-email-messages) section and returned in the response.&#x20;

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

```typescript
// Collect the input email message and email address ids however makes sense 
// for your implementation.
let emailMessageId = // ...
let emailAddressId = // ...
try {
    const input: GetEmailMessageWithBodyInput = {
        id: emailMessageId,
        emailAddressId: emailAddressId,
    }
    const result = await emailClient.getEmailMessageWithBody(input)
    // If the `id` matches an email message, `EmailMessageWithBody` will be returned, else `undefined` is returned.
} catch {
    // Handle/notify user of error 
}
```

{% endtab %}

{% tab title="Swift" %}

```swift
// Collect the input email message and email address ids however makes sense 
// for your implementation.
let emailMessageId = // ...
let emailAddressId = // ...
do {
    let input = GetEmailMessageWithBodyInput(
        id: emailMessageId,
        emailAddressId: emailAddressId
    )
    let result = try emailClient.getEmailMessageWithBody(input)
    // If the `id` matches an email message, `EmailMessageWithBody` will be returned, else `nil`
} catch {
    // Handle/notify user of error 
}
```

{% endtab %}

{% tab title="Kotlin" %}

<pre class="language-kotlin"><code class="lang-kotlin"><strong>// Collect the input email message and email address ids however makes sense 
</strong><strong>// for your implementation.
</strong><strong>val emailMessageId = // ...
</strong>val emailAddressId = // ...
launch {
    try {
        val input = GetEmailMessageWithBodyInput(
            id = emailMessageId,
            emailAddressId = emailAddressId
        )
        val result = withContext(Dispatchers.IO) {
            emailClient.getEmailMessageWithBody(input)
        }
        // If the [id] matches an email message, [EmailMessageWithBody] will be returned, else [null]
    } catch (e: EmailMessageException) {
        // Handle/notify user of exception
    }
}
</code></pre>

{% endtab %}
{% endtabs %}

## Subscribing to Email Message Events

Consumers of the **Email SDK** may choose to subscribe to notifications of events and changes to email messages. This is done via the `subscribeToEmailMessages` method. Calling the email message subscription methods in the SDK ensures that data relating to email messages will be returned as they are received on the Email Service.

{% hint style="danger" %}
It is important to use subscriptions sparingly as they are resource intensive. It is recommended to only use them when a specific view is open. For example, it would be appropriate for the application to subscribe when a view of a list of emails is in the foreground. When the user navigates from this view, the application should cancel the subscription.
{% endhint %}

{% tabs %}
{% tab title="Typescript" %}
**Setting Up A Subscription**

The `subscribeToEmailMessages` function takes two parameters; a unique `subscriptionId` to identify the specific subscription and an `EmailMessageSubscriber` object. The `EmailMessageSubscriber` will contain the functions necessary to handle changes to `EmailMessage` objects as well as updates to the `ConnectionState` which will be either `Connected` or `Disconnected`.

The `EmailMessageSubscriber` object must contain the following four functions:

```typescript
const emailMessageSubscriber: EmailMessageSubscriber = {
    emailMessageCreated(emailMessage: EmailMessage): void {
        // Implement handling for email message created behaviour
    },
    emailMessageUpdated(emailMessage: EmailMessage): void {
        // Implement handling for email message updated behaviour
    },
    emailMessageDeleted(emailMessage: EmailMessage): void {
        // Implement handling for email message deleted behaviour
    },
    connectionStatusChanged(state: ConnectionState): void {
        // Implement handling for subscription connection status changed
    }
}
```

You can then call `subscribeToEmailMessages` as so:

```typescript
await emailClient.subscribeToEmailMessages(subscriptionId, emailMessageSubscriber)
```

**Cancelling A Subscription**

To cancel a subscription, call the `unsubscribeFromEmailMessages` method with the `subscriptionId`. For example:

```typescript
emailClient.unsubscribeFromEmailMessages(subscriptionId)
```

{% endtab %}

{% tab title="Swift" %}
To subscribe to email message changes, use the `subscribe` method. This method accepts a unique subscription identifier and a subscriber object which must implement the `notify(notification: SubscriptionNotification)` method.  This handler should contain application-specific implementation of behavior in the event of a email message change. The subscription object should also implement the `connectionStatusChanged(state: SubscriptionConnectionState)` method which is invoked in the event of subscription connection state changes between `connected` and `disconnected`. This handler allows the consumer to detect when the subscription connection has been lost and take appropriate corrective action.

**Setting Up A Subscription**

To setup the subscription for created events, create a `Subscriber` conforming instance and provide it to the subscription method as so:

```swift
class MessageCreatedSubscriber: Subscriber {

    func notify(notification: SubscriptionNotification) {
        if case .messageCreated(let createdMessage) = notification {
            // Handle the created message.
        }
    }

    func connectionStatusChanged(state: SubscriptionConnectionState) {
        switch state {
        case .connected:
            // The subscription has become active.
        case .disconnected:
            // The subscription has become inactive and the subscriber
            // has been automatically unsubscribed.
        }
    }
}    
let subscriber = MessageCreatedSubscriber()
let id = UUID().uuidString
try await emailClient.subscribe(id: id, notificationType: .messageCreated, subscriber: subscriber)
```

To setup the subscription for updated events, call the subscription method as so:

```swift
class MessageUpdatedSubscriber: Subscriber {

    func notify(notification: SubscriptionNotification) {
        if case .messageUpdated(let updatedMessage) = notification {
            // Handle the updated message.
        }
    }

    func connectionStatusChanged(state: SubscriptionConnectionState) {
        switch state {
        case .connected:
            // The subscription has become active.
        case .disconnected:
            // The subscription has become inactive and the subscriber
            // has been automatically unsubscribed.
        }
    }
}    
let subscriber = MessageUpdatedSubscriber()
let id = UUID().uuidString
try await emailClient.subscribe(id: id, notificationType: .messageUpdated, subscriber: subscriber)
```

To setup the subscription for deleted events, call the subscription method as so:

```swift
class MessageDeletedSubscriber: Subscriber {

    func notify(notification: SubscriptionNotification) {
        if case .messageDeleted(let deletedMessage) = notification {
            // Handle the deleted message.
        }
    }

    func connectionStatusChanged(state: SubscriptionConnectionState) {
        switch state {
        case .connected:
            // The subscription has become active.
        case .disconnected:
            // The subscription has become inactive and the subscriber
            // has been automatically unsubscribed.
        }
    }
}    
let subscriber = MessageDeletedSubscriber()
let id = UUID().uuidString
try await emailClient.subscribe(id: id, notificationType: .messageDeleted, subscriber: subscriber)
```

{% hint style="warning" %}
Any errors that arise during the setup of the subscription will be returned via a thrown exception, so make sure to wrap your calls in a do-catch block to handle any failed behavior.
{% endhint %}

**Cancelling A Subscription**

To cancel a subscription, pass the same `id` value  used to subscribe to the `unsubscribe` method:

<pre class="language-swift"><code class="lang-swift"><strong>await emailClient.unsubscribe(id: id)
</strong></code></pre>

This will ensure that the subscription is cancelled and system resources are freed.  Alternatively you can cancel all subscriptions at once:

```swift
await emailClient.unsubscribeAll()
```

{% endtab %}

{% tab title="Kotlin" %}
To subscribe to email messages, use the `subscribeToEmailMessages` method. This method accepts a unique subscription identifier and a subscriber object which must implement the `emailMessageChanged(emailMessage: EmailMessage, type: ChangeType)` method. This handler should contain application-specific implementation of behavior in the event of a email message change. The subscription object should also implement the `connectionStatusChanged(state: ConnectionState)` method which is invoked in the event of subscription connection state changes between `CONNECTED` and `DISCONNECTED`. This handler allows the consumer to detect when the subscription connection has been lost and take appropriate corrective action.

**Setting Up A Subscription**

```kotlin
launch {
    try {
        withContext(Dispatchers.IO) {
            emailClient.subscribeToEmailMessages('subscription-id', object : EmailMessageSubscriber {
                override fun emailMessageChanged(emailMessage: EmailMessage, type: ChangeType) {
                    when (type) {
                        ChangeType.CREATED -> {
                            // Implement handling for email message created behaviour
                        }
                        ChangeType.UPDATED -> {
                            // Implement handling for email message updated behaviour
                        }
                        ChangeType.DELETED -> {
                            // Implement handling for email message deleted behaviour
                        }
                    }
                }            
                override fun connectionStatusChanged(state: Subscriber.ConnectionState) {
                   // Implement handling for subscription connection status changed
                }
            })
        }
    } catch (e: EmailMessageException) {
        // Handle/notify user of exception
    }
}
```

**Cancelling A Subscription**

To cancel a subscription, use the `unsubscribeFromEmailMessages` or `unsubscribeAllFromEmailMessages` method. For example:

```kotlin
val subscriptionId = // From where the subscription was set up
launch {
    try {
        emailClient.unsubscribeFromEmailMessages(subscriptionId)
        // or
        emailClient.unsubscribeAllFromEmailMessages()
    } catch (e: EmailMessageException) {
        // Handle/notify the user of exception
    }
}
```

This will ensure that the subscription is cancelled and system resources are freed.
{% endtab %}
{% endtabs %}

If the `subscribe` method is called more than once with the same subscription id, subsequent invocations will replace the earlier subscriptions.

## Updating Metadata of Email Messages

Updating email message metadata is supported as a batch operation. Note that this API does not allow updating the email message content and headers but rather certain attributes which make up part of the metadata.

The update email messages API currently supports updating the following email message attributes:

|          |                                                                         |
| -------- | ----------------------------------------------------------------------- |
| folderId | Update this attribute to move email messages between different folders. |
| seen     | Update this attribute to set the seen status of the email message       |

One or more email message identifiers can be passed into the `updateEmailMessages` method to perform a batch update of the email messages associated with those identifiers.

{% hint style="danger" %}
Email messages can only be updated in batches of 100. Supplying identifiers to the input which exceed this limit will throw a `LimitExceededError`.
{% endhint %}

A `BatchOperationResult` type is returned from this method call which contains the status of the batch update operation. Three possible statuses can be returned:

| Status  | Definition                                                                                                                                                                                                        |
| ------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Success | All of the email messages succeeded to update. The return object will include a list of each email message's identifier, created and updated timestamps.                                                          |
| Partial | Only a subset of email messages succeeded to update. The return object will include a list of identifiers and error descriptions of email messages which failed the update and a list which succeeded the update. |
| Failure | All of the email messages failed to update. The return object will include a list of identifiers and error descriptions of email messages which failed the update.                                                |

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

```typescript
// Collect the input message ids however makes sense for your implementation.
const ids = ['message-id-1', 'message-id-2']
try {
    const result = await emailClient.updateEmailMessages({
        ids,
        values: { seen: true },
    })
    // `result` contains the status of the batch update operation and associated success and failure metadata.
} catch {
    // Handle/notify user of error
}
```

{% endtab %}

{% tab title="Swift" %}

```swift
/// Collect the input message ids however makes sense for your implementation.
let ids = ['message-id-1', 'message-id-2']
let input = UpdateEmailMessagesInput(
    ids: ids,
    values: UpdateEmailMessagesValues(
        folderId: "\(emailAddressId)-TRASH",
        seen: true
    )
)
do {
    let result = try await emailClient.updateEmailMessages(withInput: input)
    // `result` contains the status of the batch update operation and associated success and failure metadata.
} catch {
    /// Handle/notify user of error
}
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
// Collect the input message ids however makes sense for your implementation.
val ids = listOf("message-id-1", "message-id-2")
launch {
    try {
        val input = UpdateEmailMessagesInput(
            ids = ids,
            values = UpdateEmailMessagesInput.UpdatableValues(
                folderId = "$emailAddressId-TRASH", 
                seen = true
            )
        )
        val result = withContext(Dispatchers.IO) {
            emailClient.updateEmailMessages(input)
        }
        // [result] contains the status of the batch update operation and associated success and failure metadata.
    } catch (e: EmailMessageException) {
        // Handle/notify user of exception
    }
}
```

{% endtab %}
{% endtabs %}

## Deleting Email Messages

Deleting email messages is supported as a batch operation. Deleting email messages is not the same as moving them to the trash folder. See the [Updating Metadata of Email Messages](#updating-metadata-of-email-messages) section for moving email messages to the trash folder and other folders.

{% hint style="warning" %}
By deleting the email message, the message data and metadata will no longer be available and all traces will be deleted permanently.
{% endhint %}

One or more email message identifiers can be passed into the `deleteEmailMessages` method to perform a batch delete of the email messages associated with those identifiers.

{% hint style="danger" %}
Email messages can only be deleted in batches of 100. Supplying identifiers to the input which exceed this limit will throw a `LimitExceededError`.
{% endhint %}

A `BatchOperationResult` type is returned from this method call which contains the status of the batch delete operation. Three possible statuses can be returned:

| Status  | Definition                                                                                                                                                                           |
| ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Success | All of the email messages succeeded to delete. The return object will include a list of identifiers of messages which succeeded to delete.                                           |
| Partial | Only a subset of email messages succeeded to delete. The return object will include a list of identifiers of messages which failed the delete and a list which succeeded the delete. |
| Failure | All of the email messages failed to delete. The return object will include a list of identifiers of messages which failed to delete.                                                 |

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

```typescript
// Collect the input message ids however makes sense for your implementation.
const ids = ['message-id-1', 'message-id-2']
try {
    const result = await emailClient.deleteEmailMessages(
        ids
    )
    // `result` contains the status of the batch delete operation and associated success and failure ids.
} catch {
    // Handle/notify user of error
}
```

{% endtab %}

{% tab title="Swift" %}

```swift
/// Collect the email message ids however makes sense for your implementation.
let ids = ['message-id-1', 'message-id-2']
do {
    let result = try await self.emailClient.deleteEmailMessages(
        withIds: ids
    )
    // `result` contains the status of the batch delete operation and associated success and failure ids.
} catch {
    /// Handle/notify user of error
}
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
// Collect the input message ids however makes sense for your implementation.
val ids = listOf("message-id-", "message-id-2")
launch {
    try {
        val result = withContext(Dispatchers.IO) {
            emailClient.deleteEmailMessages(ids)
        }
        // [result] contains the status of the batch delete operation and associated success and failure ids.
    } catch (e: EmailMessageException) {
        // Handle/notify user of exception
    }
}
```

{% endtab %}
{% endtabs %}

## Forwarded/Replied To State

When a new email message is sent, a new entity is created, with its `repliedTo` and `forwarded` fields set to `false` by default; this indicates that it is the first message in a thread. If this new message is in reply to, or is forwarding an existing message, it references the ID of the original message. In such cases, the `repliedTo` field of the original message is updated to `true` if it is a reply, or the `forwarded` field is updated to `true` if it is a forward.

This approach helps to maintain an accurate record of the relationships between different email message entities within the conversation thread.

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

```typescript
// Collect the original email message ID however makes sense
// for your implementation.
const messageId: string = // ...
const emailMessageHeader: InternetMessageFormatHeader = {
    from: { emailAddress: "from@bar.com" },
    to: [{ emailAddress: "to@bar.com" }],
    cc: [],
    bcc: [],
    replyTo: [],
    subject: "Example subject line",
}
```

To update the `repliedTo` property of the original email message, set the `replyingMessageId` property on the send input:

```typescript
const sendInput: SendEmailMessageInput = {
    senderEmailAddressId: "<sender-id>",
    emailMessageHeaders: emailMessageHeader,
    body: "An example email body",
    attachments: [],
    inlineAttachments: [],
    replyingMessageId: messageId,
}
```

To update the `forwarded` property of the original email message, set the `forwardingMessageId` property on the send input:

```typescript
const sendInput: SendEmailMessageInput = {
    senderEmailAddressId: "<sender-id>",
    emailMessageHeaders: emailMessageHeader,
    body: "An example email body",
    attachments: [],
    inlineAttachments: [],
    forwardingMessageId: messageId,
}
```

Once `sendEmailMessage` has successfully completed, the changes to `repliedTo` and/or `forwarded` properties can be observed on the original email message.

```typescript
try {
    await emailClient.sendEmailMessage(sendInput)
    
    const getEmailMessageInput: GetEmailMessageInput = {
        id: messageId,
        cachePolicy: CachePolicy.RemoteOnly
    }
    const emailMessage = await emailClient.getEmailMessage(
        getEmailMessageInput
    )
    // Change(s) can be observed in
    //     `emailMessage.repliedTo`
    //     `emailMessage.forwarded`
} catch {
    // ...
}
```

{% endtab %}

{% tab title="Swift" %}

```swift
// Collect the original email message ID however makes sense
// for your implementation.
let messageId: String = // ...
let emailMessageHeader = InternetMessageFormatHeader(
    from: EmailAddressDetail(emailAddress: "from@bar.com"),
    to: [EmailAddressDetail(emailAddress: "to@bar.com")],
    cc: [],
    bcc: [],
    replyTo: [],
    subject: "Example subject line"
)
```

To update the `repliedTo` property of the original email message, set the `replyingMessageId` property on the send input:

```swift
var sendInput = SendEmailMessageInput(
    senderEmailAddressId: "<sender-id>",
    emailMessageHeaders: emailMessageHeader,
    body: "An example email body",
    attachments: [],
    inlineAttachments: [],
    replyingMessageId: messageId
)
```

To update the `forwarded` property of the original email message, set the `forwardingMessageId` property on the send input:

```swift
var sendInput = SendEmailMessageInput(
    senderEmailAddressId: "<sender-id>",
    emailMessageHeaders: emailMessageHeader,
    body: "An example email body",
    attachments: [],
    inlineAttachments: [],
    forwardingMessageId: messageId
)
```

Once `sendEmailMessage` has successfully completed, the changes to `repliedTo` and/or `forwarded` properties can be observed on the original email message.

```swift
do {
    await emailClient.sendEmailMessage(sendInput)

    let getEmailMessageInput = GetEmailMessageInput(id: messageId)
    let emailMessage = await emailClient.getEmailMessage(withInput: input)
    // Change(s) can be observed in
    //     `emailMessage.repliedTo`
    //     `emailMessage.forwarded`
} catch {
    // ...
}
```

{% endtab %}

{% tab title="Kotlin" %}

```kotlin
// Collect the original email message ID however makes sense
// for your implementation.
val messageId: String = // ...
val emailMessageHeader = InternetMessageFormatHeader(
    from = EmailMessage.EmailAddress("from@bar.com"),
    to = listOf(EmailMessage.EmailAddress("to@bar.com")),
    cc = emptyList<String>(),
    bcc = emptyList<String>(),
    replyTo = emptyList<String>(),
    subject = "Example subject line",
)
```

To update the `repliedTo` property of the original email message, set the `replyingMessageId` property on the send input:

```kotlin
val sendInput = SendEmailMessageInput(
    senderEmailAddressId = "<sender-id>",
    emailMessageHeaders = emailMessageHeader,
    body = "An example email body",
    attachments = emptyList<EmailAttachment>(),
    inlineAttachments = emptyList<EmailAttachment>(),
    replyingMessageId = messageId,
)
```

To update the `forwarded` property of the original email message, set the `forwardingMessageId` property on the send input:

```kotlin
val sendInput = SendEmailMessageInput(
    senderEmailAddressId = "<sender-id>",
    emailMessageHeaders = emailMessageHeader,
    body = "An example email body",
    attachments = emptyList<EmailAttachment>(),
    inlineAttachments = emptyList<EmailAttachment>(),
    forwardingMessageId = messageId,
)
```

Once `sendEmailMessage` has successfully completed, the changes to `repliedTo` and/or `forwarded` properties can be observed on the original email message.

```kotlin
launch {
    try {
        val sendResult = withContext(Dispatchers.IO) {
            emailClient.sendEmailMessage(sendInput)
        }
        
        val getEmailMessageInput = GetEmailMessageInput(
            id = emailMessageId
        )
        val emailMessage = withContext(Dispatchers.IO) {
            emailClient.getEmailMessage(input)
        }
        // Change(s) can be observed in
        //     `emailMessage.repliedTo`
        //     `emailMessage.forwarded`
    } catch (e: EmailMessageException) {
        // ...
    }
}
```

{% endtab %}
{% endtabs %}

{% hint style="info" %}
No changes are made to the subject line, message body or headers; only the metadata of the email message is updated.
{% endhint %}
