Send and receive messages

Updated

Shows how to implement sending and receiving these messages using the Agora Chat SDK.

After logging in to Chat, users can send the following types of messages to a peer user, a chat group, or a chat room:

  • Text messages, including hyperlinks and emojis.

  • Attachment messages, including image, voice, video, and file messages.

  • Location messages.

  • CMD messages.

  • Extended messages.

  • Custom messages.

The Chat message feature is language agnostic. End users can send messages in any language, as long as their devices support input in that language.

In addition to sending messages, users can also forward one or more messages. When forwarding multiple messages, users have the following options:

  • Forward messages one-by-one
  • Forward combined messages as message history

This page shows how to implement sending, receiving, forwarding multiple messages, and modifying sent messages using the Chat SDK.

Understand the tech

The Chat SDK uses the IChatMessage and Message classes to send, receive, and withdraw messages.

The process of sending and receiving a message is as follows:

  1. The message sender creates a text, file, or attachment message using the corresponding Create method.
  2. The message sender calls SendMessage to send the message.
  3. The message recipient calls AddChatManagerDelegate to listen for message events and receive the message in the OnMessageReceived callback.

Prerequisites

Before proceeding, ensure that you meet the following requirements:

  • You have integrated the Chat SDK, initialized the SDK, and implemented the functionality of registering accounts and login. For details, see Chat SDK quickstart.

    Use Chat SDK 1.2 or higher if you intend to enable users to forward multiple messages, or to modify sent messages.

  • You understand the API call frequency limits as described in Limitations.

Implementation

This section shows how to implement sending and receiving the various types of messages.

Send a text message

Use the Message class to create a text message, and IChannelManager to send the message.

// Call CreateTextSendMessage to create a text message.
// Set `content` as the content of the text message.
// Set `conversationId` to the user ID of the peer user in one-to-one chat, group ID in group chat, and chat room ID in room chat.
Message msg = Message.CreateTextSendMessage(conversationId, content);
// Set `MessageType` in `Message` as `Chat`, `Group`, or `Room` for one-to-one chat, group chat, or room chat.
msg.MessageType = MessageType.Group;
// Set the priority of chat room messages. The default priority is `RoomMessagePriority.Normal`, indicating the normal priority.
// msg.MessageType = MessageType.Room;
// msg.SetRoomMessagePriority(RoomMessagePriority.High);
// Call SendMessage to send the message.
// When sending the message, you can instantiate a `Callback` object to listen for the result of the message sending.
// You can also update the message state in this callback, for example, by adding a pop-up box that reminds the message sending fails.
SDKClient.Instance.ChatManager.SendMessage(ref msg, new CallBack(
  onSuccess: () => {
    Debug.Log($"{msg.MsgId} Message sending succeeds.");
  },
  onError:(code, desc) => {
    Debug.Log($"{msg.MsgId} Message sending fails, errCode={code}, errDesc={desc}");
  }
));

Send a message to online users only

Agora Chat supports delivering messages only to users that are currently online. An example of using this function is displaying the votes in a group voting: Only users that are online need to see the changes in real time, while the others only need the final result.

All types of messages in one-to-one chats and chat groups support this function. Compared to an ordinary message, a message that is delivered only to online users has the following differences:

  • Does not support offline storage: If the recipient is offline when sending a message, the message cannot be received, even after logging in again. For ordinary messages, when the recipient is online, the message reminder is received in real time; when the recipient is offline, the offline push message is sent in real time. When the recipient is online again, the Chat server actively pushes the offline message to the client.
  • Support local storage: After a message is successfully sent, it is added to the database.
  • Roaming storage is not supported by default: Sent messages are not stored on the Chat message server by default, so users cannot obtain the messages on other devices. If you need to activate roaming storage of online messages, contact support@agora.io.

To deliver messages only to online users, set Message#deliverOnlineOnly to true when sending the message. The following is an example of sending a text message to only online users:

// Create a text message, `content` is the text content of the message.
// `conversationId` is the message receiver. It is the peer user ID in single chat and the group ID in group chat.
Message message = Message.CreateTextSendMessage(conversationId, content);
// Whether the message is only delivered to online users. (Default) `false`: Delivered regardless of whether the user is online or not; `true`: Only delivered to online users. If the user is offline, the message will not be delivered.
message.DeliverOnlineOnly = true;
// Conversation type: Single chat is MessageType.Chat, group chat is MessageType.Group, the default is single chat.
message.MessageType = MessageType.Chat;
// Send a message.
SDKClient.Instance.ChatManager.SendMessage(ref message, new CallBack(
    onSuccess: () => {
    },
    onError: (code, desc) => {
    }
));

Set message priority

In high-concurrency use-cases, you can set a certain message type or messages from a chat room member as high, normal, or low priority. In this case, low-priority messages are dropped first to reserve resources for the high-priority ones, for example, gifts and announcements, when the server is overloaded. This ensures that the high-priority messages can be dealt with first when loads of messages are being sent in high concurrency or high frequency. Note that this feature can increase the delivery reliability of high-priority messages, but cannot guarantee the deliveries. Even high-priorities messages can be dropped when the server load goes too high.

You can set the priority for all types of messages in the chat room. See code example above.

Receive a message

You can use IChatManagerDelegate to listen for message events. You can add multiple IChatManagerDelegates to listen for multiple events. When you no longer listen for an event, ensure that you remove the delegate.

When a message arrives, the recipient receives an OnMessagesReceived callback. Each callback contains one or more messages. You can traverse the message list, and parse and render these messages in this callback and render these messages.

// Inherit and instantiate IChatManagerDelegate.
public class ChatManagerDelegate : IChatManagerDelegate {
    // Listen for OnMessagesReceived.
    public void OnMessagesReceived(List messages)
    {
      // Traverse the message list, and parse and render the messages.
    }
}
// Add the delegate to listen for message callback.
ChatManagerDelegate adelegate = new ChatManagerDelegate();
SDKClient.Instance.ChatManager.AddChatManagerDelegate(adelegate);
// Remove the delegate.
SDKClient.Instance.ChatManager.RemoveChatManagerDelegate(adelegate);

Recall a message

After a message is sent, you can recall it. The RecallMessage method recalls a message that is saved both locally and on the server, whether it is a historical message, offline message or a roaming message on the server, or a message in the memory or local database of the message sender or recipient.

The default time limit for recalling a message is two minutes. You can extend this time frame to up to 7 days in Agora Console. To do so, select a project that enables Agora Chat, then click Configure > Features > Message recall.

The following permission rules apply to message recall:

  • In one-to-one chats, only the message sender can recall a message they sent. If the message has expired, the recall fails.
  • In chat groups and chat rooms, regular members can recall only the messages they sent, and the recall fails if the message has expired. Since SDK v1.4.0, the chat group owner, chat room owner, and admins can recall messages sent by other members, even after those messages have expired.

  1. Except CMD messages, you can recall all types of message. 2. If an attachment message, like an image, voice, video, or file message, is recalled, the attachment of the message is also deleted.
// Call `RecallMessage` to recall the message.
SDKClient.Instance.ChatManager.RecallMessage("Message ID", new CallBack(
  onSuccess: () => {
    Debug.Log("Message recall succeeds.");
  },
  onProgress: (progress) => {
    Debug.Log($"Message recall progress {progress}");
  },
  onError: (code, desc) => {
    Debug.Log($"Message recall fails, errCode={code}, errDesc={desc}");
  }
 ));

You can also use IChatManagerDelegate to listen for the message withdraw state:

// The SDK triggers OnMessageRecalled when the message is withdrawn.
void OnMessagesRecalled(List messages);

Send and receive an attachment message

Voice, image, video, and file messages are essentially attachment messages. This section introduces how to send these types of messages.

Send and receive a voice message

Before sending a voice message, you should implement audio recording on the app level, which provides the URI and duration of the recorded audio file.

Refer to the following code example to create and send a voice message:

// Call CreateVoiceSendMessage to create a voice message.
// Set `localPath` as the path of the audio file on the local device, `displayName` as the display name of the message, `fileSize` as the size of the audio file, and `duration` as the duration (in seconds) of the audio file. For audio files, you can set `displayName` as "".
Message msg = Message.CreateVoiceSendMessage(toChatUsername, localPath, displayName, fileSize, duration);
// Set the message type using the `MessageType` attribute in `Message`.
// You can set `MessageType` as `Chat`, `Group`, or `Room`, which indicates whether to send the message to a peer user, a chat group, or a chat room.
msg.MessageType = MessageType.Group;
// Call SendMessage to send the message.
// When sending the message, you can instantiate a `Callback` object to listen for the result of the message sending. You can also update the message state in this callback, for example, by adding a pop-up box that reminds the message sending fails.
SDKClient.Instance.ChatManager.SendMessage(ref msg, new CallBack(
  onSuccess: () => {
    Debug.Log($"{msg.MsgId} Message sending succeeds.");
  },
  onProgress: (progress) => {
    Debug.Log($"Message sending progress {progress}");
  },
  onError:(code, desc) => {
    Debug.Log($"{msg.MsgId}Message sending fails, errCode={code}, errDesc={desc}");
  }
));

When the recipient receives the message, refer to the following code example to get the audio file:

// "Message ID" is the ID of the message returned in the onSuccess callback after the SDK successfully sends the message.
Message msg = SDKClient.Instance.ChatManager.LoadMessage("Message ID");
if (msg != null)
{
  ChatSDK.MessageBody.VoiceBody vb = (ChatSDK.MessageBody.VoiceBody)msg.Body;
  // RemotePath indicates the path of the audio file on the server.
  string voiceRemoteUrl = vb.RemotePath;
  // LocalPath indicates the path of the audio file on the local device.
  string voiceLocalUri = vb.LocalPath;
}
else {
  Debug.Log($"Fails to find the message");
}

Send and receive an image message

By default, the SDK compresses the image file before sending it. To send the original file, you can set original as true.

Refer to the following code example to create and send an image message:

// Create SendMessage to send the image message.
// Set `localPath` as the path of the image file on the local device, `displayName` as the display name of the message, `fileSize` as the size of the image file, `width` as the width (in pixels) of the thumbnail, and `height` as the height (in pixels) of the thumbnail.
// `original` indicates whether to send the original image file. The default value is `false`. By default, the SDK compresses image files the exceeds 100 KB and sends the thumbnail. To send the original image, set this parameter as `true`.
Message msg = Message.CreateImageSendMessage(toChatUsername,localPath, displayName, fileSize, original, width , height);
// Set the message type using the `MessageType` attribute in `Message`.
// You can set `MessageType` as `Chat`, `Group`, or `Room`, which indicates whether to send the message to a peer user, a chat group, or a chat room.
msg.MessageType = MessageType.Group;
// Call SendMessage to send the message.
// When sending the message, you can instantiate a `Callback` object to listen for the result of the message sending. You can also update the message state in this callback, for example, by adding a pop-up box that reminds the message sending fails.
SDKClient.Instance.ChatManager.SendMessage(ref msg, new CallBack(
  onSuccess: () => {
    Debug.Log($"{msg.MsgId} Message sends succeeds.");
  },
  onProgress: (progress) => {
    Debug.Log($"Message sending progress {progress}");
  },
  onError:(code, desc) => {
    Debug.Log($"{msg.MsgId} Message sending fails, errCode={code}, errDesc={desc}");
  }
));

When the recipient receives the message, refer to the following code example to get the thumbnail and attachment file of the image message:

// "Message ID" is the ID of the message returned in the onSuccess callback after the SDK successfully sends the message.
Message msg = SDKClient.Instance.ChatManager.LoadMessage("Message ID");
if (msg != null)
{
  ChatSDK.MessageBody.ImageBody ib = (ChatSDK.MessageBody.ImageBody)msg.Body;
  // RemotePath indicates the path of the image file on the server.
  string imgRemoteUrl = ib.RemotePath;
  // ThumbnaiRemotePath indicates the path of the thumbnail on the server.
  string thumbnailUrl = ib.ThumbnaiRemotePath;
  // LocalPath indicates the path of the image file on the local device.
  string imgLocalUri = ib.LocalPath;
  // ThumbnailLocalPath indicates the path of the thumbnail on the local device.
  Uri thumbnailLocalUri = ib.ThumbnailLocalPath;
}
else {
  Debug.Log($"Fails to find the message.");
}

If Options.IsAutoDownload is set as true on the recipient's client, the SDK automatically downloads the thumbnail after receiving the message. If not, you need to call SDKClient.Instance.ChatManager.DownloadThumbnail to download the thumbnail and get the path from the ThumbnailLocalPath member in msg.Body.

Send and receive a GIF image message

Since SDK v1.4.0, you can send and receive GIF image messages. A GIF image message is a subtype of image message that is not compressed when sent. Thumbnail generation and download are the same as for a regular image message.

To send a GIF image message, set the isGif property of the ImageBody to true:

Message msg = Message.CreateImageSendMessage(toChatUsername, localPath);
// Set the isGif property of the image body to true.
ImageBody imageBody = (ImageBody)msg.Body;
imageBody.isGif = true;
SDKClient.Instance.ChatManager.SendMessage(ref msg, new CallBack(
  onSuccess: () => { },
  onError: (code, desc) => { }
));

As with a regular message, the recipient receives the OnMessagesReceived callback. After confirming that the message is an image message, read the isGif property of the message body. If it returns true, the message is a GIF image message.

public void OnMessagesReceived(List<Message> messages)
{
    foreach (var msg in messages)
    {
        if (msg.Body is ImageBody imageBody)
        {
            if (imageBody.isGif == true)
            {
                // Handle the GIF image message according to your business logic, for example, download and display it.
            }
        }
    }
}

Send and receive a video message

Before sending a video message, you should implement video capturing on the app level, which provides the duration of the captured video file.

Refer to the following code example to create and send a video message:

Message msg = Message.CreateVideoSendMessage(toChatUsername, localPath, displayName, thumbnailLocalPath, fileSize, duration, width, height);
// Call SendMessage to send the message.
// When sending the message, you can instantiate a `Callback` object to listen for the result of the message sending. You can also update the message state in this callback, for example, by adding a pop-up box that reminds the message sending fails.
SDKClient.Instance.ChatManager.SendMessage(ref msg, new CallBack(
  onSuccess: () => {
    Debug.Log($"{msg.MsgId} Messag sending succeeds");
  },
  onProgress: (progress) => {
    Debug.Log($"Message sending progress {progress}");
  },
  onError:(code, desc) => {
    Debug.Log($"{msg.MsgId} Message sending fails, errCode={code}, errDesc={desc}");
  }
));

By default, when the recipient receives the message, the SDK downloads the thumbnail of the video message.

If you do not want the SDK to automatically download the video thumbnail, set Options.IsAutoDownload as false, and to download the thumbnail, you need to call SDKClient.Instance.ChatManager.DownloadThumbnail, and get the path of the thumbnail from the ThumbnailLocalPath member in msg.Body.

To download the actual video file, call SDKClient.Instance.ChatManager.DownloadAttachment, and get the path of the video file from the LocalPath member in msg.Body.

// When the recipient receives a video message, the SDK downloads and then open the video file.
SDKClient.Instance.ChatManager.DownloadAttachment("Message ID", new CallBack(
  onSuccess: () => {
    Debug.Log($"Attachment download succeeds.");
    Message msg = SDKClient.Instance.ChatManager.LoadMessage("Message ID");
    if (msg != null)
    {
      if (msg.Body.Type == ChatSDK.MessageBodyType.VIDEO) {
        ChatSDK.MessageBody.VideoBody vb = (ChatSDK.MessageBody.VideoBody)msg.Body;
        // LocalPath indicates the path of the video file on the local device.
        string videoLocalUri = vb.LocalPath;
        // You add open the video file after getting the path.
      }
    }
    else {
      Debug.Log($"Fails to find the message.");
    }
  },
  onProgress: (progress) => {
    Debug.Log($"Attachment download progress {progress}");
  },
  onError: (code, desc) => {
    Debug.Log($"Attachment download fails, errCode={code}, errDesc={desc}");
  }
));

Send and receive a file message

Refer to the following code example to create, send, and receive a file message:

// Call CreateFileSendMessage to create a file message.
// Set `localPath` as the path of the file on the local device, `displayName` as the display name of the file message, and `fileSize` as the size of the file.
Message msg = Message.CreateFileSendMessage(toChatUsername,localPath, displayName, fileSize);
// Set the message type using the `MessageType` attribute in `Message`.
// You can set `MessageType` as `Chat`, `Group`, or `Room`, which indicates whether to send the message to a peer user, a chat group, or a chat room.
msg.MessageType = MessageType.Group;
// Call SendMessage to send the message.
// When sending the message, you can instantiate a `Callback` object to listen for the result of the message sending. You can also update the message state in this callback, for example, by adding a pop-up box that reminds the message sending fails.
SDKClient.Instance.ChatManager.SendMessage(ref msg, new CallBack(
  onSuccess: () => {
    Debug.Log($"{msg.MsgId} Message sending succeeds.");
  },
  onProgress: (progress) => {
    Debug.Log($"Message sending progress {progress}");
  },
  onError:(code, desc) => {
    Debug.Log($"{msg.MsgId} Message sending fails, errCode={code}, errDesc={desc}");
  }
));
// When the recipient receives the message, call `LoadMessage` to get the attachment file.
// "Message ID" is the ID of the message returned in the onSuccess callback after the SDK successfully sends the message.
Message msg = SDKClient.Instance.ChatManager.LoadMessage("Message ID");
if (msg != null)
{
  ChatSDK.MessageBody.FileBody fb = (ChatSDK.MessageBody.FileBody)msg.Body;
  // RemotePath indicates the path of the file on the server.
  string fileRemoteUrl = fb.RemotePath;
  // LocalPath indicates the path of the file on the local device.
  string fileLocalUri = fb.LocalPath;
}
else {
  Debug.Log($"Fails to find the message.");
}

Send a location message

To send and receive a location message, you need to integrate a third-party map service provider. When sending a location message, you get the longitude and latitude information of the location from the map service provider; when receiving a location message, you extract the received longitude and latitude information and display the location on the third-party map.

// Call CreateLocationSendMessage to create a location message.
// Set `locationAddress` as the address of the location and `buildingName` as the the name of the building.
Message msg = Message.CreateLocationSendMessage(toChatUsername, latitude, longitude, locationAddress, buildingName);
SDKClient.Instance.ChatManager.SendMessage(ref msg, new CallBack(
  onSuccess: () => {
    Debug.Log($"{msg.MsgId} Message sending succeeds.");
  },
  onError:(code, desc) => {
    Debug.Log($"{msg.MsgId} Message sending fails, errCode={code}, errDesc={desc}");
  }
));

Send and receive a CMD message

CMD messages are command messages that instruct a specified user to take a certain action. The recipient deals with the command messages themselves.

CMD messages are not stored in the local database.Actions beginning with em_ and easemob:: are internal fields. Do not use them.

// Use `action` to customize the message
string action = "actionXXX";
Message msg = Message.CreateCmdSendMessage(toChatUsername, action);
SDKClient.Instance.ChatManager.SendMessage(ref msg, new CallBack(
   onSuccess: () => {
      Debug.Log($"{msg.MsgId} Message sending succeeds.");
   },
   onError: (code, desc) => {
      Debug.Log($"{msg.MsgId} Message sending fails, errCode={code}, errDesc={desc}");
   }
));

To notify the recipient that a CMD message is received, use a separate delegate so that users can deal with the message differently.

// Inherit and instantiate `IChatManagerDelegate`.
public class ChatManagerDelegate : IChatManagerDelegate {
    // Occurs when the message is received.
    public void OnMessagesReceived(List messages)
    {
      // Traverse, parse, and display the message.
    }
    // Occurs when a CMD message is received.
    void OnCmdMessagesReceived(List messages)
    {
      // Traverse, parse, and display the message.
    }
}
// Call AddChatManagerDelegate to add a message delegate.
ChatManagerDelegate adelegate = new ChatManagerDelegate()
SDKClient.Instance.ChatManager.AddChatManagerDelegate(adelegate);

Send a customized message

The following code example shows how to create and send a customized message:

// Set `event` as the customized message type, for example, gift.
string event = "gift";
Dictionary adict = new Dictionary();
adict.Add("key", "value");
// Call CreateCustomSendMessage to create a customized message.
Message msg = Message.CreateCustomSendMessage(toChatUsername, event, adict);
SDKClient.Instance.ChatManager.SendMessage(ref msg, new CallBack(
   onSuccess: () => {
      Debug.Log($"{msg.MsgId} Message sending succeeds.");
   },
   onError: (code, desc) => {
      Debug.Log($"{msg.MsgId} Message sending fails, errCode={code}, errDesc={desc}");
   }
));

Use message extensions

If the message types listed above do not meet your requirements, you can use message extensions to add attributes to the message. This can be applied in more complicated messaging use-cases.

Message msg = Message.CreateTextSendMessage(toChatUsername, content);
// Add message attributes.
AttributeValue attr1 = AttributeValue.Of("value", AttributeValueType.STRING);
AttributeValue attr2 = AttributeValue.Of(true, AttributeValueType.BOOL);
msg.Attributes.Add("attribute1", attr1);
msg.Attributes.Add("attribute2", attr2);
// Send the message.
SDKClient.Instance.ChatManager.SendMessage(ref msg, new CallBack(
  onSuccess: () => {
    Debug.Log($"{msg.MsgId}发送成功");
  },
  onError:(code, desc) => {
    Debug.Log($"{msg.MsgId}发送失败,errCode={code}, errDesc={desc}");
  }
));
// When the recipient receives the message, get the extension attributes.
bool found = false;
string str = msg.GetAttributeValue(msg.Attributes, "attribute1", found);
if (found) {
  // Use variable str.
}
found = false
bool b = msg.GetAttributeValue(msg.Attributes, "attribute2", found);
if (found) {
  // Use variable b.
}

Forward a single message

You can use the Message#CreateSendMessage method and Message#Attributes property to create a message that is exactly the same as the original message by passing in the message body and extended fields of the original message (if any), and then call the ChatManager#sendMessage method to forward the message.

You can forward all types of messages in individual chats, chat groups, chat rooms, and sub-areas. For messages with attachments, there's no need to re-upload the attachments during forwarding.

However, if the original message expires (for example, deleted from the server due to storage limitations), the recipient can view the attachment address after forwarding but won't be able to download the attachment.

To forward a single message, refer to the following code:

// messageId is the message ID to be forwarded.
// string messageId = "xxx";

// When a message is obtained based on the message ID, it will automatically contain the body content and extended attributes of the original message.
Message targetMessage = SDKClient.Instance.ChatManager.LoadMessage(messageId);

if (targetMessage != null)
{
     // to: Single chat is the peer user ID, group chat is the group ID, and chat room chat is the chat room ID.
     string to = "the conversationId you want to send to";

     // Create a new message based on the to and message body.
     Message newMessage = Message.CreateSendMessage(to, targetMessage.Body);
     newMessage.Attributes = targetMessage.Attributes;

     // The chat type defaults to single chat MessageType.Chat. For group chats or chat rooms, the MessageType needs to be set to MessageType.Group or MessageType.Room.
     // newMessage.MessageType = MessageType.Group;

     SDKClient.Instance.ChatManager.SendMessage(ref newMessage, new CallBack(
         onSuccess: () => {
         },
         onError: (code, desc) => {
         }
     ));
}

Forward multiple messages

Supported types for forwarded messages include text, images, audio & video files, attachment, and custom messages. A user can create a combined message with a list of original messages and send it. When receiving a combined message, the recipient can select it and other messages to create a new layered combined message. A combined message can contain up to 10 layers of messages, with at most 300 messages at each layer.

To forward and receive combined messages, refer to the following code:

  1. Create a combined message using multiple message IDs:

    String title = "Historical messages for one-to-one chats between A and B";
    String summary = "A: These are historical messages from A. \nB: These are historical messages from B.";
    String compatibleText = "Your current version does not support this type of message. Please upgrade to the latest version.";
    Message msg = Message.CreateCombineSendMessage(to, title, summary, compatibleText, msgIdList);
    
    SDKClient.Instance.ChatManager.SendMessage(ref msg, new CallBack(
        onSuccess: () => {
            // Handling logic upon sending success
        },
        onError: (code, desc) => {
            // Handling logic if sendMessage fails
        }
    ));
  2. Download and parse combined messages:

    SDKClient.Instance.ChatManager.FetchCombineMessageDetail(msg, new ValueCallBack>(
        onSuccess: (list) => {
            // Add the handling logic and show the message list
        },
        onError: (code, desc) => {
            // Handle an error
        }
    ));

For further details see Multiple messages forwarding limitations.

Modify sent messages

For messages that have been sent successfully, the SDK supports modifying the message content.

  • Before SDK v1.4.0, you could only modify text messages sent in one-to-one chats and chat groups.
  • Since SDK v1.4.0, you can modify various message types sent in one-to-one chats, chat groups, and chat rooms:
    • Text and custom messages: modify both the message body and the extension attributes (attributes).
    • File, video, voice, image, location, and combined messages: modify the extension attributes (attributes) only.
    • Command messages: modification is not supported.

There is no time limit for modifying a message, that is, it can be modified as long as the message is still stored on the server. After the message is modified, the message life cycle, that is, its storage time on the server, is recalculated. For example, a message can be stored on the server for 180 days, and the user modifies it on the 30th day after the message was sent. Instead of remaining 150 days, the message can be now stored on the server for 180 days after successful modification.

In the modified message, the message ID remains unchanged. The message body, the extension attributes, or both are edited and the following items are added:

  • The operator ID of the user performing the action.
  • The operation time that indicates when the message was edited.
  • The number of times a message is edited (up to 10 times).

For the edited message, other information included in the message, such as the message sender and recipient, remains unchanged.

To modify a sent message, refer to the following code:

  1. Call ModifyMessage with the message ID, the new message body, and the new extension attributes:

    // Text message: you can modify both the message body and the extension attributes.
    TextBody textBody = new TextBody("new content");
    Dictionary<string, AttributeValue> attributes = new Dictionary<string, AttributeValue>();
    attributes["newkey"] = AttributeValue.Of("new value", AttributeValueType.STRING);
    // The body and attributes cannot both be null.
    SDKClient.Instance.ChatManager.ModifyMessage("msgId", textBody, attributes, new ValueCallBack<Message>(
        onSuccess: (msg) => { },
        onError: (code, desc) => { }
    ));
    
    // Custom message: you can modify both the message body and the extension attributes.
    CustomMessageBody customBody = new CustomMessageBody("new action");
    SDKClient.Instance.ChatManager.ModifyMessage("msgId", customBody, attributes, new ValueCallBack<Message>(
        onSuccess: (msg) => { },
        onError: (code, desc) => { }
    ));
    
    // File, video, voice, image, location, or combined message: you can modify the extension attributes only. Pass null as the message body.
    SDKClient.Instance.ChatManager.ModifyMessage("msgId", null, attributes, new ValueCallBack<Message>(
        onSuccess: (msg) => { },
        onError: (code, desc) => { }
    ));
  2. Receive notification of messages modified by other users:

    // Inherit and implement `IChatManagerDelegate`.
    public class ChatManagerDelegate : IChatManagerDelegate {
    
        public void OnMessageContentChanged(Message msg, string operatorId, long operationTime)
        {
            // You can obtain operatorId and operationTime as follows:
            // string id = msg.Body.OperatorId;
            // long time = msg.Body.OperationTime;
        }
      }
    
    // Add a delegate.
    ChatManagerDelegate adelegate = new ChatManagerDelegate();
    SDKClient.Instance.ChatManager.AddChatManagerDelegate(adelegate);
    
    // Remove the delegate when it is no longer required.
    SDKClient.Instance.ChatManager.RemoveChatManagerDelegate(adelegate);

For further details see Sent message modification limitations.

Next steps

After implementing sending and receiving messages, you can refer to the following documents to add more messaging functionalities to your app: