Send messages
This guide covers how to send messages in direct channels, group channels, and open channels using the Nexconn SDK.
By default, users who have not joined an open channel can still send messages to it. To restrict this, go to the Nexconn Console, navigate to Chat > Chat settings > Open Channels, and enable Restrict messaging to joined participants. This setting does not affect server-side APIs.
Message content types
The Message object's content property holds either a standard message content (MessageContent subclass) or a media message content (MediaMessageContent subclass).
| Feature | Content type | Base class | Description |
|---|---|---|---|
| Text message | TextMessage | MessageContent | Plain text content. |
| Quote reply | ReferenceMessage | MediaMessageContent | Quoted message content for reply functionality. |
| Image message | ImageMessage | MediaMessageContent | Image content with original image support. |
| GIF message | GIFMessage | MediaMessageContent | Animated GIF content. |
| File message | FileMessage | MediaMessageContent | File attachment content. |
| Voice message | HDVoiceMessage | MediaMessageContent | High-quality voice recording content. |
| Mention (@) | N/A | N/A | Not a predefined type. See Send a mention message. |
These are some of the built-in message content types. You can also create custom content types and send them with channel.sendMessage(). See Custom message types.
- Channel-based architecture: Obtain a channel object (e.g.,
GroupChannel,DirectChannel) before sending messages. - Unified API: Use
channel.sendMessage()for all message types, including media messages. - Rate limit: The client SDK limits sending to 5 messages per second.
Get a channel object
Before sending a message, obtain the target channel object using the type-specific factory method:
- Kotlin
- Java
// Use the type-specific factory method (recommended)
val groupChannel = GroupChannel(groupId)
val directChannel = DirectChannel(userId)
val openChannel = OpenChannel(openChannelId)
// Use the type-specific factory method
GroupChannel groupChannel = new GroupChannel(groupId);
DirectChannel directChannel = new DirectChannel(userId);
OpenChannel openChannel = new OpenChannel(openChannelId);
Send a text message
Text messages are the most common message type. The following example sends a text message to a group channel.
- Kotlin
- Java
// 1. Get the channel object
val groupChannel = GroupChannel(groupId)
// 2. Configure send parameters (message content + optional push config)
val params = SendMessageParams(TextMessage("Hello, World!")).apply {
pushConfig = PushConfig().apply {
pushContent = "You received a new message"
pushData = """{"key":"value"}"""
}
}
// 3. Send the message
groupChannel.sendMessage(params, object : SendMessageHandler {
override fun onAttached(message: Message) {
// Message saved to local database — update the UI
Log.d("SendMessage", "Saved to DB, messageId: ${message.messageId}")
updateMessageUI(message)
}
override fun onResult(message: Message, error: NCError?) {
if (error == null) {
Log.d("SendMessage", "Message sent successfully")
markMessageAsSent(message)
} else {
Log.e("SendMessage", "Send failed: ${error.message}")
handleSendError(message, error)
}
}
})
// 1. Get the channel object
GroupChannel groupChannel = new GroupChannel(groupId);
// 2. Configure send parameters (message content + optional push config)
SendMessageParams params = new SendMessageParams(new TextMessage("Hello, World!"));
PushConfig pushConfig = new PushConfig();
pushConfig.setPushContent("You received a new message");
pushConfig.setPushData("{\"key\":\"value\"}");
params.setPushConfig(pushConfig);
// 3. Send the message
groupChannel.sendMessage(params, new SendMessageHandler() {
@Override
public void onAttached(Message message) {
Log.d("SendMessage", "Saved, messageId: " + message.getMessageId());
updateMessageUI(message);
}
@Override
public void onResult(Message message, NCError error) {
if (error == null) {
Log.d("SendMessage", "Message sent successfully");
markMessageAsSent(message);
} else {
Log.e("SendMessage", "Send failed: " + error.getMessage());
handleSendError(message, error);
}
}
});
Sending to different channel types
// Direct channel
val directChannel = DirectChannel(userId)
directChannel.sendMessage(params, handler)
// Group channel
val groupChannel = GroupChannel(groupId)
groupChannel.sendMessage(params, handler)
// Open channel
val openChannel = OpenChannel(chatRoomId)
openChannel.sendMessage(params, handler)
// Community channel
val communityChannel = CommunityChannel(communityId)
communityChannel.sendMessage(params, handler)
Send an image message
Image messages support both original and compressed images. The SDK handles compression and thumbnail generation automatically.
- Kotlin
- Java
// 1. Get the channel object
val channel = DirectChannel(userId)
// 2. Configure send parameters (image content + optional push config)
val params = SendMediaMessageParams(
ImageMessage().apply {
localPath = "file:///path/to/image.jpg"
original = true // true: send original, false: send compressed
}
).apply {
pushConfig = PushConfig().apply {
pushContent = "You received an image"
}
}
// 3. Send the media message
channel.sendMediaMessage(params, object : SendMediaMessageHandler {
override fun onAttached(message: Message) {
updateMessageUI(message)
}
override fun onProgress(message: Message, progress: Int) {
Log.d("Upload", "Upload progress: $progress%")
updateUploadProgress(message, progress)
}
override fun onResult(message: Message, error: NCError?) {
if (error == null) {
Log.d("SendMedia", "Image sent successfully")
markMessageAsSent(message)
} else {
Log.e("SendMedia", "Image send failed: ${error.message}")
handleSendError(message, error)
}
}
override fun onCanceled(message: Message) {
Log.d("SendMedia", "Image send canceled")
}
})
// 1. Get the channel object
DirectChannel channel = new DirectChannel(userId);
// 2. Configure send parameters (image content + optional push config)
ImageMessage imageMessage = new ImageMessage();
imageMessage.setLocalPath("file:///path/to/image.jpg");
imageMessage.setOriginal(true);
SendMediaMessageParams params = new SendMediaMessageParams(imageMessage);
PushConfig pushConfig = new PushConfig();
pushConfig.setPushContent("You received an image");
params.setPushConfig(pushConfig);
// 3. Send the media message
channel.sendMediaMessage(params, new SendMediaMessageHandler() {
@Override
public void onAttached(Message message) {
updateMessageUI(message);
}
@Override
public void onProgress(Message message, int progress) {
Log.d("Upload", "Upload progress: " + progress + "%");
updateUploadProgress(message, progress);
}
@Override
public void onResult(Message message, NCError error) {
if (error == null) {
Log.d("SendMedia", "Image sent successfully");
markMessageAsSent(message);
} else {
Log.e("SendMedia", "Image send failed: " + error.getMessage());
handleSendError(message, error);
}
}
@Override
public void onCanceled(Message message) {
Log.d("SendMedia", "Image send canceled");
}
});
Image compression
The SDK handles image compression automatically:
- Thumbnail: Generated at 30% quality, longest side capped at 240 px.
- Compressed: If
originalis not set, the image is compressed at 85% quality, longest side capped at 1080 px. - Original: If
original = true, no compression is applied.
Modifying the default compression settings is generally not recommended.
Send a file message
File messages support any file type.
- Kotlin
- Java
val params = SendMediaMessageParams(
FileMessage().apply {
localPath = "file:///path/to/document.pdf"
name = "document.pdf"
size = fileSize
}
).apply {
pushConfig = PushConfig().apply {
pushContent = "You received a file"
}
}
channel.sendMediaMessage(params, object : SendMediaMessageHandler {
override fun onAttached(message: Message) { updateMessageUI(message) }
override fun onProgress(message: Message, progress: Int) { updateUploadProgress(message, progress) }
override fun onResult(message: Message, error: NCError?) { if (error == null) markMessageAsSent(message) else handleSendError(message, error) }
override fun onCanceled(message: Message) { }
})
DirectChannel channel = new DirectChannel(userId);
FileMessage fileMessage = new FileMessage();
fileMessage.setLocalPath("file:///path/to/document.pdf");
fileMessage.setName("document.pdf");
fileMessage.setSize(fileSize);
SendMediaMessageParams params = new SendMediaMessageParams(fileMessage);
PushConfig pushConfig = new PushConfig();
pushConfig.setPushContent("You received a file");
params.setPushConfig(pushConfig);
channel.sendMediaMessage(params, new SendMediaMessageHandler() {
@Override
public void onAttached(Message message) { updateMessageUI(message); }
@Override
public void onProgress(Message message, int progress) { updateUploadProgress(message, progress); }
@Override
public void onResult(Message message, NCError error) { if (error == null) markMessageAsSent(message); else handleSendError(message, error); }
@Override
public void onCanceled(Message message) { }
});
File size limits
- GIF files: 2 MB max
- Other files: 100 MB max
Send a voice message
Voice messages carry audio recordings.
- Kotlin
- Java
val params = SendMediaMessageParams(
HDVoiceMessage().apply {
localPath = "file:///path/to/audio.amr"
duration = audioDuration
}
)
channel.sendMediaMessage(params, object : SendMediaMessageHandler {
override fun onAttached(message: Message) { }
override fun onProgress(message: Message, progress: Int) { }
override fun onResult(message: Message, error: NCError?) { if (error == null) markMessageAsSent(message) else handleSendError(message, error) }
override fun onCanceled(message: Message) { }
})
DirectChannel channel = new DirectChannel(userId);
HDVoiceMessage voiceMessage = new HDVoiceMessage();
voiceMessage.setLocalPath("file:///path/to/audio.amr");
voiceMessage.setDuration(audioDuration);
SendMediaMessageParams params = new SendMediaMessageParams(voiceMessage);
channel.sendMediaMessage(params, new SendMediaMessageHandler() {
@Override
public void onAttached(Message message) { }
@Override
public void onProgress(Message message, int progress) { }
@Override
public void onResult(Message message, NCError error) { if (error == null) markMessageAsSent(message); else handleSendError(message, error); }
@Override
public void onCanceled(Message message) { }
});
Upload media to your own server
You can send files hosted on your own server. Pass the remote URL when constructing the media message content. In this case, the file is not uploaded to Nexconn servers, and there is no file size limit. Use the sendMessage method directly.
If you want the SDK to send the message only after you upload the file, upload the file yourself and then use sendMessage with the remote URL directly:
- Kotlin
- Java
// 1. Upload your file to your server first
val remoteUrl = uploadToMyServer(localFilePath)
// 2. Create the message content with the remote URL
val imageContent = ImageMessage().apply {
this.remoteUrl = remoteUrl
}
// 3. Send the message using sendMessage (not sendMediaMessage)
val params = SendMessageParams(imageContent)
channel.sendMessage(params, object : SendMessageHandler {
override fun onAttached(message: Message) {}
override fun onResult(message: Message, error: NCError?) {}
})
// 1. Upload your file to your server first
String remoteUrl = uploadToMyServer(localFilePath);
// 2. Create the message content with the remote URL
ImageMessage imageMessage = new ImageMessage();
imageMessage.setRemoteUrl(remoteUrl);
// 3. Send the message using sendMessage (not sendMediaMessage)
SendMessageParams params = new SendMessageParams(imageMessage);
channel.sendMessage(params, new SendMessageHandler() {
@Override
public void onAttached(Message message) {}
@Override
public void onResult(Message message, NCError error) {}
});
Send a mention message
Mentions (@) are not a predefined message type (see Message type overview). Instead, Nexconn embeds mentionedInfo data within messages to enable mention functionality.
The [MentionedInfo] field in MessageContent stores information about mentioned users. Both built-in and custom message types inherit [MessageContent], so they all support mentions.
Nexconn supports adding mentionedInfo when sending messages to group channels and community channels. Construct a MentionedInfo object and set it on the MessageContent before sending.
List<String> userIdList = new ArrayList<>();
userIdList.add("userId1");
userIdList.add("userId2");
MentionedInfo mentionedInfo = new MentionedInfo(MentionedType.USER, userIdList, null);
TextMessage messageContent = new TextMessage("Hello team");
messageContent.setMentionedInfo(mentionedInfo);
MentionedInfo parameters
| Parameter | Type | Description |
|---|---|---|
| type | MentionedType | Required. MentionedType.ALL mentions everyone. MentionedType.USER mentions specific users listed in userIdList. |
| userIdList | List<String> | The list of mentioned user IDs. Required when type is USER. Also supported when type is ALL to additionally highlight specific users. |
| mentionedContent | String | The push notification content shown when a mention triggers an offline push. If null, a default message like "Someone mentioned you" is displayed. This overrides all other pushContent settings. |
The following example sends a text message mentioning specific users in a group channel:
- Kotlin
- Java
val params = SendMessageParams(
TextMessage("Hello team").apply {
mentionedInfo = MentionedInfo(
type = MentionedType.USER,
userIdList = listOf("userId1", "userId2"),
mentionedContent = null
)
}
)
GroupChannel("groupId").sendMessage(params, object : SendMessageHandler {
override fun onAttached(message: Message) {}
override fun onResult(message: Message, error: NCError?) {}
})
TextMessage textMessage = new TextMessage("Hello team");
List<String> userIdList = new ArrayList<>();
userIdList.add("userId1");
userIdList.add("userId2");
MentionedInfo mentionedInfo = new MentionedInfo(MentionedType.USER, userIdList, null);
textMessage.setMentionedInfo(mentionedInfo);
SendMessageParams params = new SendMessageParams(textMessage);
GroupChannel groupChannel = new GroupChannel("groupId");
groupChannel.sendMessage(params, new SendMessageHandler() {
@Override
public void onAttached(Message message) {}
@Override
public void onResult(Message message, NCError error) {}
});
After receiving a message, extract the MentionedInfo to handle mentions in your UI:
- Kotlin
- Java
val mentionedInfo = message.content?.mentionedInfo
MentionedInfo mentionedInfo = message.getContent().getMentionedInfo();
Push notifications
Open channels do not support missed messages or push notifications.
If your app has third-party push services configured in Nexconn, the server sends push notifications when the recipient is offline, based on the message type, supported push channels, and the recipient's Do Not Disturb settings.
Push notifications appear in the system notification bar. Built-in message types display default notification titles and content. For details, see User content message formats.
To customize push notification titles, content, and other attributes, use PushConfig via SendMessageParams.pushConfig or SendMediaMessageParams.pushConfig.
Configure message push properties
Set a PushConfig on SendMessageParams.pushConfig (or SendMediaMessageParams.pushConfig) to customize its push behavior:
- Custom push title and content
- Additional push data
- Force display of notification content regardless of recipient settings
- Push template ID
- Kotlin
- Java
val pushConfig = PushConfig().apply {
pushTitle = title
pushContent = content
pushData = data
forceShowDetailContent = forceDetail
templateId = ""
}
val params = SendMessageParams(textMessage).apply {
this.pushConfig = pushConfig
}
PushConfig pushConfig = new PushConfig();
pushConfig.setPushTitle(title);
pushConfig.setPushContent(content);
pushConfig.setPushData(data);
pushConfig.setForceShowDetailContent(forceDetail);
pushConfig.setTemplateId("");
SendMessageParams params = new SendMessageParams(textMessage);
params.setPushConfig(pushConfig);
Push notifications for custom messages
Built-in message types have default push notification content (see User content message formats). For custom message types, you must provide a pushContent field; otherwise, offline push notifications will not be sent.
- If a custom message type needs push support, provide
pushContentinPushConfigvia the send parameters (SendMessageParams.pushConfig). - If a custom message type does not need push support (e.g., it serves as a business-layer command), leave
pushContentempty.
To enable push notifications for custom messages, always provide pushContent. Without it, the recipient will not receive offline push notifications.
Disable push for a message
By default, the server triggers push notifications when a recipient is offline. To suppress push for a specific message, set disableNotification to true in SendMessageParams or SendMediaMessageParams.
- Kotlin
- Java
val params = SendMessageParams(TextMessage("Message content")).apply {
disableNotification = true
}
DirectChannel("targetId").sendMessage(params, handler)
SendMessageParams params = new SendMessageParams(new TextMessage("Message content"));
params.setDisableNotification(true);
new DirectChannel("targetId").sendMessage(params, handler);
When the recipient comes back online, missed messages (cached for up to 7 days) are automatically delivered for direct, group, and system channels. Community channel messages do not support the missed message mechanism and must be fetched manually.
Pass custom data
To transmit custom data to the other party:
- MessageContent extra field: Set via
MessageContent.extra. This field is sent with the message to the other party. Do not confuse withMessage.extra, which is local-only. - Push data (
pushData): Set viaPushConfig.pushDatain the send parameters. Push data is only delivered when a push notification is triggered. Retrieve it on the receiving end from the push notification payload.
Handle send failures
For stored message types (see Message type overview), if the onAttached callback fires, the message has been saved to the local database and is in the message list.
- If saving fails, check whether the parameters are valid and whether local storage is writable.
- If saving succeeds but sending fails (
onResultwith a non-null error), display the failed message in the UI and cache theMessageinstance fromonResult. Resend later by passing the same instance tosendMessage/sendMediaMessage. Creating a new message with the same content results in a duplicate entry in the local message list.
For non-stored message types, cache and retry the message instance, or create a new one.
Forward and broadcast messages
Forward messages: The Chat SDK does not provide a dedicated forwarding API. Use the standard send message API to forward message content.
Broadcast messages: To send a message to multiple users (or multiple target IDs), consider:
- Loop through the client send message API. Note the rate limit of 5 messages per second.
- Use the server-side IM API from your backend. The Send direct message API supports sending to multiple users in a single call. You can also use Send group message and Send open channel message to send to multiple groups or open channels.