Provides your users the ability to perform email communications with a Sudo
Sending Email Messages
The Email SDK can handle sending email messages. Sending messages requires a provisioned email address as discussed in Manage Email Addresses.
We support using a raw RFC 822 payload to allow flexible email composition within your application.
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.
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.
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:
fileName
mimeType
contentId
Key Attachment/s
"Secure Data n"
"application/x-sudoplatform-key"
"securekeyexchangedata@sudoplatform.com"
Body Attachment
"Secure Email"
"application/x-sudoplatform-body"
"securebody@sudoplatform.com"
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.
// Collect the input headers, body, attachments and sender email address id // however makes sense for your implementation.constsenderEmailAddressId:string=// ...constemailMessageHeader: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",}constemailAttachment:EmailAttachment= { filename:"fooAttachment.pdf", contentId:uuid.v4(), mimeType:"application/pdf", inlineAttachment:false, data:// ... Some pdf data}constinlineAttachment:EmailAttachment= { filename:"fooImage.png", contentId:uuid.v4(), mimeType:"image/png", inlineAttachment:true, data:// ... Some image data}try {constinput:SendEmailMessageInput= { senderEmailAddressId: senderEmailAddressId, emailMessageHeaders: emailMessageHeader, body:"An example email body", attachments: [emailAttachment], inlineAttachments: [inlineAttachment], }constresult=awaitemailClient.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 }
/// 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 =tryawait 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}
// 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 }}
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:
The user must be entitled to send emails by thesudoplatform.email.emailMessageSendUserEntitled entitlement.
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.
See Email Entitlements for an overview of how the Email service integrates with the Sudo Platform Entitlements system.
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 section for information on the subscription method and see the 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:
The user must be entitled to receive emails by thesudoplatform.email.emailMessageReceiveUserEntitled entitlement.
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.
See Email Entitlements for an overview of how the Email service integrates with the Sudo Platform Entitlements system.
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.
If an email message has been deleted, it will no longer be available for access.
A fetch of single or multiple email messages can be performed remotely or locally by specifying the appropriate CachePolicy 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. This method will return the record if it exists.
try {constemailMessage=awaitemailClient.getEmailMessage({ id, cachePolicy:CachePolicy.RemoteOnly, })// `emailMessage` contains the email message object, else `undefined` if not found.} catch {// Handle/notify user of errors}
/// Collect the input id of the email message object.let input =GetEmailMessageInput( id: input.messageId, cachePolicy: .remoteOnly)do {let emailMessage =tryawait emailClient.getEmailMessage( withInput: input)// `emailMessage` contains the email message object, else `nil` if not found.} catch {// Handle/notify user of errors}
val emailMessageId = emailMessage.idlaunch {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 }}
Multiple Email Messages
The ability to retrieve multiple email messages available to the user is supported. These results can be paginated.
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.
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.
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.
Note that both timestamps cannot be specified, otherwise an InvalidArgument error will occur.
All Email Messages
To retrieve multiple email messages that are owned by the signed in user, call the listEmailMessages method.
constdateRange:EmailMessageDateRange= { updatedAt: { startDate:// startDate as a `Date` object endDate: // endDate as a `Date` object }}try {constresult=awaitemailClient.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}
let dateRange =EmailMessageDateRange( updatedAt: DateRange( startDate:// startDate as a `Date` object endDate:// endDate as a `Date` object))let input =ListEmailMessagesInput( dateRange: dateRange, cachePolicy: .remoteOnly, sortOrder: .asc, limit:10, nextToken:nil)do {let result =tryawait 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}
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 }}
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.
// Collect the input email address id however makes sense for your implementation.constemailAddressId=emailAddress.idconstdateRange:EmailMessageDateRange= { updatedAt: { startDate:// startDate as a `Date` object endDate: // endDate as a `Date` object }}try {constresult=awaitemailClient.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}
// Collect the input email address id however makes sense for your implementation.let emailAddressId = emailAddress.idlet dateRange =EmailMessageDateRange( updatedAt: DateRange( startDate:// startDate as a `Date` object endDate:// endDate as a `Date` object))let input =ListEmailMessagesForEmailAddressInput( emailAddressId: emailAddressId, dateRange: dateRange, cachePolicy: .remoteOnly, sortOrder: .asc, limit:10, nextToken:nil)do {let result =tryawait 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}
// Collect the input email address id however makes sense for your implementation.val emailAddressId = emailAddress.idval 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 }}
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.
// Collect the input email folder id however makes sense for your implementation.constemailFolderId=emailFolder.idconstdateRange:EmailMessageDateRange= { updatedAt: { startDate:// startDate as a `Date` object endDate: // endDate as a `Date` object }}try {constresult=awaitemailClient.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}
// Collect the input email folder id however makes sense for your implementation.let emailFolderId = emailFolder.idlet dateRange =EmailMessageDateRange( updatedAt: DateRange( startDate:// startDate as a `Date` object endDate:// endDate as a `Date` object))let input =ListEmailMessagesForEmailFolderIdInput( emailFolderId: emailFolderId, dateRange: dateRange, cachePolicy: .remoteOnly, sortOrder: .asc, limit:10, nextToken:nil)do {let result =tryawait 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}
// Collect the input email folder id however makes sense for your implementation.val emailFolderId = emailFolder.idval 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 }}
By default, list email messages API have a limit of 1MB of data when no limit is supplied.
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 data. While there are a number of internet standards, such as RFC 2822, RFC 5322 and RFC 6854, 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.
try {constrfc822Data=awaitemailClient.getEmailMessageRfc822Data({ id, cachePolicy =CachePolicy.REMOTE_ONLY })// If the `id` matches an email message, `rfc822Data` will be returned, else `undefined` is returned.if (rfc822Data) {constemailMessageWithBody=// parse the `rfc822Data` }} catch {// Handle/notify user of error }
// Collect the input email message and email address ids however makes sense for your implementation.let emailMessageId = emailMessage.idlet emailAddressId = emailAddress.idlet input =GetEmailMessageRfc822DataInput( id: emailMessageId, emailAddressId: emailAddressId)do {let rfc822Data =tryawait 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 }
// Collect the input email message and email address ids however makes sense for your implementation.val emailMessageId = emailMessage.idval emailAddressId = emailAddress.idlaunch {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 }}
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 section and returned in the response.
// Collect the input email message and email address ids however makes sense // for your implementation.let emailMessageId =// ...let emailAddressId =// ...try {constinput:GetEmailMessageWithBodyInput= { id: emailMessageId, emailAddressId: emailAddressId, }constresult=awaitemailClient.getEmailMessageWithBody(input)// If the `id` matches an email message, `EmailMessageWithBody` will be returned, else `undefined` is returned.} catch {// Handle/notify user of error }
// 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 }
// Collect the input email message and email address ids however makes sense // for your implementation.val emailMessageId =// ...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 }}
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 thesubscribeToEmailMessages 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.
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.
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:
constemailMessageSubscriber: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 }}
There are three email message subscriptions available:
- subscribeToEmailMessageCreated(withDirection:resultHandler:)
- subscribeToEmailMessageUpdated(resultHandler:)
- subscribeToEmailMessageDeleted(resultHandler:)
Each of these methods use a closure resultHandler to allow you to decide what happens when a message is received in real-time.
A SubscriptionToken is also returned from the call to these methods. In order to ensure that the subscription remains established and connected, you must keep a strong reference to this returned object. If the reference is lost and marked for clean-up in ARC, the subscription will be cancelled and closed.
Setting Up A Subscription
To setup the subscription for created events, call the subscription method as so:
let token =tryawait emailClient.subscribeToEmailMessageCreated( withDirection: .inbound) { result inswitch result {caselet .failure(error):// Handle errorcaselet .success(emailMessage):// `emailMessage` is the new email message object received in real time.}
To setup the subscription for updated events, call the subscription method as so:
let token =tryawait emailClient.subscribeToEmailMessageUpdated { result inswitch result {caselet .failure(error):// Handle errorcaselet .success(emailMessage):// `emailMessage` is the updated email message object received in real time.}
To setup the subscription for deleted events, call the subscription method as so:
let token =tryawait emailClient.subscribeToEmailMessageDeleted { result inswitch result {caselet .failure(error):// Handle errorcaselet .success(emailMessage):// `emailMessage` is the deleted email message object received in real time.}
It is important to ensure that token is not lost until the subscription is no longer needed.
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.
Cancelling A Subscription
To cancel a subscription, use the cancel() method on the SubscriptionToken. For example:
token.cancel()
This will ensure that the subscription is cancelled and system resources are freed.
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
launch {try {withContext(Dispatchers.IO) { emailClient.subscribeToEmailMessages('subscription-id', object : EmailMessageSubscriber {overridefunemailMessageChanged(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 } } } overridefunconnectionStatusChanged(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:
val subscriptionId =// From where the subscription was set uplaunch {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.
If the subscribeToEmailMessages 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.
Email messages can only be updated in batches of 100. Supplying identifiers to the input which exceed this limit will throw a LimitExceededError.
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.
// Collect the input message ids however makes sense for your implementation.constids= ['message-id-1','message-id-2']try {constresult=awaitemailClient.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}
/// 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 =tryawait 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}
// 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 }}
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 section for moving email messages to the trash folder and other folders.
By deleting the email message, the message data and metadata will no longer be available and all traces will be deleted permanently.
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.
Email messages can only be deleted in batches of 100. Supplying identifiers to the input which exceed this limit will throw a LimitExceededError.
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.
// Collect the input message ids however makes sense for your implementation.constids= ['message-id-1','message-id-2']try {constresult=awaitemailClient.deleteEmailMessages( ids )// `result` contains the status of the batch delete operation and associated success and failure ids.} catch {// Handle/notify user of error}
/// Collect the email message ids however makes sense for your implementation.let ids = ['message-id-1', 'message-id-2']do {let result =tryawait 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}
// 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 }}
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.
// Collect the original email message ID however makes sense// for your implementation.constmessageId:string=// ...constemailMessageHeader: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:
Once sendEmailMessage has successfully completed, the changes to repliedTo and/or forwarded properties can be observed on the original email message.
try {awaitemailClient.sendEmailMessage(sendInput)constgetEmailMessageInput:GetEmailMessageInput= { id: messageId, cachePolicy:CachePolicy.RemoteOnly }constemailMessage=awaitemailClient.getEmailMessage( getEmailMessageInput )// Change(s) can be observed in// `emailMessage.repliedTo`// `emailMessage.forwarded`} catch {// ...}
// 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:
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:
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.
do {await emailClient.sendEmailMessage(sendInput)let getEmailMessageInput =GetEmailMessageInput( id: messageId, cachePolicy: .remoteOnly)let emailMessage =await emailClient.getEmailMessage(withInput: { id: messageId })// Change(s) can be observed in// `emailMessage.repliedTo`// `emailMessage.forwarded`} catch {// ...}
// 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:
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:
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.