Skip to main content

Send Message

This document explains how to send messages from the client SDK, applicable to one-to-one chat, group chat, and chatroom scenarios.

warning

The client SDK has a message frequency limit - a maximum of 5 messages can be sent per second.

Sending Messages

sendMessage is the fundamental interface in IMLib for message transmission, supporting both built-in and custom message types. For specific message types, IMLib also provides multiple convenient syntactic sugar methods.

Interface

RongIMLib.sendMessage(conversation, message, options)

Parameters

ParameterTypeRequiredDescription
conversationIConversationOptionYesTarget conversation
messageBaseMessageYesMessage instance to be sent. Must be a subclass of BaseMessage, either IMLib built-in messages (e.g., RongIMLib.TextMessage) or custom message instances registered via RongIMLib.registerMessageType()
optionsISendMessageOptionsNoSending configuration options. Defines optional behaviors during message sending, such as expandability and push notifications

Example

The following example demonstrates how to use sendMessage to send a text message mentioning "Zhang San" in a group chat.

1. Define Target Conversation and Message Content

Since this is a group @ message, mentionedInfo needs to be added.

// Define target conversation - here we define a group conversation
const conversation = { conversationType: RongIMLib.ConversationType.GROUP, targetId: '<Target ID>' }
// Instantiate the message to be sent - RongIMLib.TextMessage is a built-in text message type
const message = new RongIMLib.TextMessage({
// Text content
content: 'Text content',
// (Optional) Additional information attached to the message, transparently transmitted to the recipient
extra: 'Additional message information',
// For group messages requiring @ mentions, add the mentionedInfo field
mentionedInfo: {
// @ type: ALL or INDIVIDUAL
type: RongIMLib.MentionedType.SINGAL,
// List of @ users
userIdList: ['zhangsan'],
// @ content
mentionedContent: ''
}
})

2. Configure Sending Options

Construct ISendMessageOptions to define sending behavior. For group @ messages, set isMentioned to true.

// Configuration properties
const options = {
// Set isMentioned to true for @ messages
isMentioned: true,
// Pre-send callback - the returned message can be used for list rendering
onSendBefore: (message) => {
console.log('Pre-send callback', message)
}
}

3. Call the Send Method

Call sendMessage and update message status based on the returned messageId.

// Send message
RongIMLib.sendMessage(conversation, message, options).then(res => {
if (res.code === RongIMLib.ErrorCode.SUCCESS) {
// On success, update the message status to "sent" using the returned messageId
console.log('Message sent successfully', res.data)
} else {
console.log('Message sending failed', res.code, res.msg)
}
})

4. Handle Failed Messages

If sending fails, mark the message status as failed using the returned messageId and provide a resend option.

Note
  • If the message doesn't reach RC servers or the server returns failure, recipients won't receive it.

  • In poor network conditions, messages might reach recipients successfully while the sender times out waiting for acknowledgment. Resending in such cases may cause duplicate messages. See FAQ for details.

5. Resending Messages

When resending, maintain identical message content to the original.

tip

Since SDK 5.5.1, you can specify the original message's messageId in options for deduplication. RC servers don't deduplicate - applications should use this ID to identify duplicates. Get messageId from the onSendBefore callback's message object or sending results.

// Define target conversation - here a group conversation
const conversation = { conversationType: RongIMLib.ConversationType.GROUP, targetId: '<Target ID>' }
// Instantiate message - RongIMLib.TextMessage is a built-in text type
const message = new RongIMLib.TextMessage({ content: 'Text content' })
// Configuration
const options = {
// Original message's messageId - obtain from onSendBefore callback or results
messageId: 0
}

RongIMLib.sendMessage(conversation, message, options).then(res => {
if (res.code === RongIMLib.ErrorCode.SUCCESS) {
// On success, update status using messageId
console.log('Message sent successfully', res.data)
} else {
// On failure, update status using messageId
console.log('Message sending failed', res.code, res.msg)
}
})

sendMessage Interface Details

sendMessage accepts three parameters: conversation, message, and options.

  • conversation defines the target conversation. See IConversationOption.

    ParameterTypeDescription
    conversationTypeConversationTypeConversation type
    targetIdstringRecipient ID
  • message contains the content to send, supporting either IMLib built-in messages (e.g., RongIMLib.TextMessage) or custom messages registered via RongIMLib.registerMessageType().

  • options defines optional sending behaviors like expandability and push. See ISendMessageOptions

    ParameterTypeDescription
    isStatusMessageboolean(Deprecated) Whether status message (optional)
    disableNotificationbooleanWhether to send silent messages (optional)
    pushContentstringPush content (optional)
    pushDatastringPush notification additional data (optional)
    isMentionedbooleanWhether @ message. Only valid for group/ultra group conversations (optional)
    mentionedType1|2(Deprecated) @ type: 1: @all 2: @specific users (optional)
    mentionedUserIdListstring[](Deprecated) List of @ user IDs (optional)
    directionalUserIdListstring[]For targeted messages, only valid for group/ultra group conversations. Note: SDK versions <5.9.4 only support groups for targeted messages. (optional)
    isVoipPushbooleanWhen recipient is iOS device and offline, they'll receive Voip Push. Doesn't affect Android. (optional)
    canIncludeExpansionbooleanWhether message can be expanded
    expansion[key: string]: stringMessage expansion data (optional)
    isFilerWhiteBlacklistbooleanBlocklist/allowlist (optional)
    pushConfigIPushConfigMobile push configuration (optional) (similar to Android/iOS MessagePushConfig)
    onSendBeforeFunctionPre-send callback (≥5.4.0)
    messageIdnumberWhen resending, specify original message's messageId. All parameters must match original message (≥5.5.1)
    disableUpdateLastMessagebooleanDisable updating conversation's last message, default false (≥5.12.2)
    needReceiptbooleanWhether read receipt is required, default false (≥5.20.0)
    • IPushConfig Parameter Details
ParameterTypeDescription
pushTitlestringPush notification title. If not set: for one-to-one chats, the sender's name is displayed; for group chats, the group name is displayed; for custom messages, no title is displayed by default
pushContentstringPush notification content
pushDatastringAdditional information for remote push notifications
iOSConfigIiOSPushConfig(Optional)
androidConfigIAndroidPushConfig(Optional)
disablePushTitlebooleanWhether to hide the push title. Only effective for iOS platform
forceShowDetailContentbooleanWhether to force push
templateIdstringPush notification template ID
harmonyOSConfigIHarmonyOSPushConfig(Optional)

Built-in Message Types

IMLib provides predefined message types including text, voice, image, GIF, file, etc.

Text Message

ITextMessageContent Parameter Details

KeyTypeRequiredDescription
contentstringYesText content

Code Example

new RongIMLib.TextMessage({ content: '' })

Image Message

IImageMessageContent Parameter Details

KeyTypeRequiredDescription
contentstringYesImage thumbnail as Base64 string. Generate the thumbnail yourself (recommended longest side ≤ 240px), encode as Base64 and put into content. Base64 string length should be around 5k, max 10k. Note: some tools add Data URI prefix when converting images to Base64, e.g. data:image/jpeg;base64,/9j/4AAQSkZJRgABAgAAZABkAAD. Remove the Data URI prefix, keeping only the data part, e.g. /9j/4AAQSkZJRgABAgAAZABkAAD.
imageUristringYesRemote access URL of the image
thumWidthnumberNoThumbnail width (supported since v5.18.0)
thumHeightnumberNoThumbnail height (supported since v5.18.0)

Code Example

new RongIMLib.ImageMessage({
content: '', // Image thumbnail as Base64 string, max 80KB
imageUri: '' // Remote access URL of the image
})

File Message

IFileMessageContent Parameter Details

KeyTypeRequiredDescription
namestringYesFile name
sizenumberYesFile size in bytes
typestringYesFile type
fileUrlstringYesRemote download URL of the file

Code Example

new RongIMLib.FileMessage({
name: '',
size: 1000,
type: '',
fileUrl: ''
})

HQ Voice Message

IHQVoiceMessageContent Parameter Details

KeyTypeRequiredDescription
remoteUrlstringYesRemote media resource URL
durationnumberYesVoice duration in seconds. Must be ≤60s
typestringNoEncoding type, default aac. If using Android/iOS IMKit SDK, use default aac format as IMKit only supports aac for recording/playback. If your app handles audio separately, other formats can be used.

Code Example

new RongIMLib.HQVoiceMessage({
remoteUrl: '<aac file URL>',
duration: 60,
})

Short Video Message

ISightMessageContent Parameter Details

KeyTypeRequiredDescription
sightUrlstringYesRemote video resource URL. If using Android/iOS IMKit SDK, must use H.264 + AAC encoded files as IMKit only supports this combination for recording/playback.
contentstringYesBase64 string of the first frame thumbnail. Generate thumbnail (recommended longest side ≤240px), encode as Base64. Length should be around 5k, max 10k. Remove any Data URI prefix from the Base64 string.
durationnumberYesVideo duration. Default server limit is 2 minutes. Contact sales to adjust.
sizenumberYesVideo size in bytes
namenumberYesVideo name

Code Example

new RongIMLib.SightMessage({
sightUrl: "<Remote video URL>",
content: "<Thumbnail base64>"
duration: 10,
size: 100,
name: "Video name"
})

GIF Message

IGIFMessageContent Parameter Details

KeyTypeRequiredDescription
gifDataSizenumberYesGIF file size in bytes
remoteUrlstringYesRemote storage URL of the GIF
widthnumberYesImage width
heightnumberYesImage height

Code Example

new RongIMLib.GIFMessage({
gifDataSize: 30,
remoteUrl: '<Image URL>',
width: 300,
height: 200
})

Reference Message

IReferenceMessageContent Parameter Details

ParameterTypeRequiredDescription
referMsgUserIdstringYesUser ID of the referenced message sender
referMsganyYesReference message object
contentstringYesInput text message content
objNamestringYesType of the referenced message

Code Example

new RongIMLib.ReferenceMessage({
referMsgUserId: '<Referenced user ID>',
referMsg: {
content: 'Referenced message text'
},
referMsgUid: 'Referenced message UId',
content: 'Message content to send',
objName: RongIMLib.MessageType.TEXT
})

Location Message

ILocationMessageContent Parameter Details

ParameterTypeRequiredDescription
longitudenumberYesLongitude
latitudenumberYesLatitude
poistringYesLocation information
contentstringYesLocation thumbnail as Base64 string without prefix

Code Example

new RongIMLib.LocationMessage({
latitude: '<Latitude>',
longitude: '<Longitude>',
poi: 'Location info',
content: '<base64>'
})

Rich Content Message

IRichContentMessageContent Parameter Details

ParameterTypeRequiredDescription
titlestringYesTitle
contentstringYesSummary content
imageUristringYesDisplay image URL
urlstringYesArticle link URL

Code Example

new RongIMLib.RichContentMessage({
title: 'Title',
content: 'Content summary',
imageUri: '<Image URL>',
url: '<Article URL>'
})

Information Notification Message

tip

Supported since v5.8.1

IInformationNotificationMessageContent Parameter Details

ParameterTypeRequiredDescription
messagestringYesNotification bar message content
extrastringNoAdditional information for the notification bar

Code Example

new RongIMLib.InformationNotificationMessage({
message: 'Notification bar message content',
extra: 'Additional information for the notification bar',
})

Command Message

tip

Supported since v5.8.1

ICommandMessageContent Parameter Details

ParameterTypeRequiredDescription
namestringYesCommand name
datastringYesCommand content

Code Example

new RongIMLib.CommandMessage({
name: 'Command name',
data: 'Command content',
})

Group Notification Message

tip

Supported since v5.8.1

IGroupNotificationMessageContent Parameter Details

ParameterTypeRequiredDescription
operatorUserIdstringYesOperator's user ID
operationstringYesOperation name for group notifications
datastringYesOperation data
messagestringYesMessage content
extrastringNoExtended information

Code Example:

new RongIMLib.GroupNotificationMessage({
operatorUserId: 'Operator user ID',
operation: 'Group notification operation name',
data: 'Operation data',
message: 'Message content'
})

Emoji Message

For web clients, simply send Emoji messages using the text message type (TextMessage).

  • RC provides an Emoji plugin with 128 built-in Emoji images. These can be used for the emoji picker in the message input box or extended with custom configurations.
  • When sending messages, you must send the native Emoji characters directly. For example: 😀. Conversion method: symbolToEmoji.
  • When receiving messages in the Web SDK, Emojis are received in Unicode format (e.g., ef600). They must be converted to display as native Emojis correctly.

Code Example:

// Define target conversation
const conversation = { conversationType: RongIMLib.ConversationType.PRIVATE, targetId: '<Target ID>' }
// Instantiate message to send - RongIMLib.TextMessage is the built-in text message type
const message = new RongIMLib.TextMessage({ content: '😀' })
// Send
RongIMLib.sendMessage(conversation, message).then(res => {})

Emoji Plugin

  • Plugin Compatibility

    ChromeFirefoxSafariIEEdgeiPhoneAndroid
    30+30+10+7+✔️iOS 8.0+ Safari and WeChat browserChrome and WeChat browser on Android 4.4+
  • Importing the Emoji Plugin

    <!-- Non-minified version -->
    <script src="https://cdn.ronghub.com/RongEmoji-2.2.11.js"></script>
    <!-- Minified version -->
    <script src="https://cdn.ronghub.com/RongEmoji-2.2.11.min.js"></script>
danger
  1. When importing the SDK via import * as RongIMLib from '@rongcloud/imlib-next', the Emoji plugin must be called with the window prefix (e.g., window.RongIMLib.RongIMEmoji.init()).
  2. The RongEmoji plugin only supports CDN import and is not available via npm.
  • Emoji Initialization (Default Parameters)

    RongIMLib.RongIMEmoji.init();
  • Emoji Initialization (Custom Configuration)

    config parameter details:

    ParameterTypeRequiredDescriptionMinimum Version
    sizeNumberNoEmoji size (default: 24, recommended: 18-58)2.2.6
    urlStringNoEmoji sprite image URL2.2.6
    langStringNoEmoji name language (default: zh)2.2.6
    extensionObjectNoCustom emoji extensions2.2.6
    // Emoji reference: http://unicode.org/emoji/charts/full-emoji-list.html
    var config = {
    size: 25,
    url: '//f2e.cn.ronghub.com/sdk/emoji-48.png',
    lang: 'en',
    extension: {
    dataSource: {
    u1F914: { // Custom emoji for u1F914
    en: 'thinking face', // English name
    zh: '思考', // Chinese name
    tag: '🤔', // Native Emoji
    position: '0 0' // Position coordinates in sprite
    }
    },
    url: '//cdn.ronghub.com/thinking-face.png' // Custom emoji sprite URL
    }
    };
    RongIMLib.RongIMEmoji.init(config);
  • Get Emoji List

    var list = RongIMLib.RongIMEmoji.list;
    /*list => [{
    unicode: 'u1F600',
    emoji: '😀',
    node: span,
    symbol: '[笑嘻嘻]'
    }]
    */
  • Emoji to Text

    Displays emoji names when native emoji rendering is unsupported (useful for message input).

    var message = '😀😁Test Emoji';
    // Convert native emojis in message to their names
    RongIMLib.RongIMEmoji.emojiToSymbol(message);
    // => '[笑嘻嘻][露齿而笑]Test Emoji'
  • Text to Emoji

    When sending messages, the message body must use native emoji characters.

    var message = '[笑嘻嘻][露齿而笑]Test Emoji';
    // Convert emoji names in message to native emojis
    RongIMLib.RongIMEmoji.symbolToEmoji(message);
    // => '😀😁Test Emoji'
  • Emoji to HTML

    After receiving messages in the Web SDK, native emoji characters are decoded into Unicode codes and require conversion for proper display.

    var message = '\uf600Test Emoji';
    // Convert native emojis (including Unicode) in message to HTML
    RongIMLib.RongIMEmoji.emojiToHTML(message);
    // => "<span class='rong-emoji-content' name='[笑嘻嘻]'>😀</span>Test Emoji"
  • Text to HTML

    var message = '[露齿而笑]Test Emoji';
    // Convert emoji names in message to HTML
    RongIMLib.RongIMEmoji.symbolToHTML(message);
    // => "<span class='rong-emoji-content' name='[露齿而笑]'>😁</span>Test Emoji"

Extended Attributes

All messages support two types of extended attributes (user and extra) for transmitting custom business data.

  • user: Carries user data in messages. Currently supports four properties: user.id, user.name, user.portraitUri, and user.extra.
  • extra: String-type data that RC does not parse. The business layer handles serialization/deserialization logic.

Code Example

new RongIMLib.TextMessage({
content: '',
extra: '',
user: {
id: '',
name: '',
portraitUri: '',
extra: ''
}
})

When sending FileMessage, ImageMessage, HQVoiceMessage, SightMessage, and GIFMessage, constructing the message instance requires a remote resource URL, which means the business layer needs to first upload the local resource to be sent before building the message instance, making the process relatively complex.

To address this, IMLib has implemented corresponding syntactic sugar methods to encapsulate both the local resource upload process and the message construction process, making it easier for the business layer to integrate.

Sending File Messages

Parameter Description

ParameterTypeRequiredDescription
conversationIConversationOptionYesConversation
msgBodyISendFileMessageOptionsYesMessage content to be sent
hooksIUploadHooksNoCallback hooks during upload
sendOptionsIUploadMessageOptionNoMessage configuration

Code Example

const conversation = {
conversationType: RongIMLib.ConversationType.PRIVATE,
targetId: ''
}
const msgBody = {
file, // File to be uploaded
user: { id: '', name: '', portraitUri: '', extra: '' }, // User information carried in the message (optional)
extra: '' // Transparent data carried in the message (optional)
}
const hooks = {
onProgress (progress) {}, // Upload progress listener (optional)
onComplete (fileInfo) { // Callback hook upon upload completion (optional)
console.log(fileInfo.url) // File storage URL
// To build a custom message, return new ABCMesssage('')
// ABCMesssage is defined via custom message implementation `const ABCMesssage = RongIMLib.registerMessageType(...)`
// If no return value is provided, SDK defaults to sending FileMessage
}
}
const options = {
contentDisposition: 'attachment' // How file links are displayed in browsers (only valid for aws, stc uploads) 'inline': preview in browser, 'attachment': direct download. If not provided, HTML files are previewed while others are downloaded directly.
// ... Other optional configurations
},

RongIMLib.sendFileMessage(
conversation,
msgBody,
hooks,
options
).then(({ code, data: message }) => {
if (code === 0) {
// Successfully sent
}
})

Sending Image Messages

Parameter Description

ParameterTypeRequiredDescription
conversationIConversationOptionYesConversation
msgBodyISendImageMessageOptionsYesMessage content to be sent
hooksIUploadHooksNoCallback hooks during upload
sendOptionsIImageMessageOptionNoMessage configuration

Code Example

const conversation = {
conversationType: RongIMLib.ConversationType.PRIVATE,
targetId: ''
}
const msgBody = {
file, // File to be uploaded
user: { id: '', name: '', portraitUri: '', extra: '' }, // User information carried in the message (optional)
extra: '' // Transparent data carried in the message (optional)
}
const hooks = {
onProgress (progress) {}, // Upload progress listener (optional)
onComplete (fileInfo) { // Callback hook upon upload completion (optional)
console.log(fileInfo.url) // File storage URL
// To build a custom message, return new ABCMesssage('')
// ABCMesssage is defined via custom message implementation `const ABCMesssage = RongIMLib.registerMessageType(...)`
// If no return value is provided, SDK defaults to sending FileMessage
}
}
const options = {
contentDisposition: 'inline' // 'inline' | 'attachment' , determines how links are displayed in browsers when using aws upload
// ... Other optional configurations
},

RongIMLib.sendImageMessage(
conversation,
msgBody,
hooks,
options
).then(({ code, data: message }) => {
if (code === 0) {
// Successfully sent
}
})

Sending High-Quality Voice Messages

tip

If your business also uses IMKit SDK for Android/iOS, please use the default aac format, as IMKit's audio recording and playback only support the aac format and cannot play other formats by default. If your Android/iOS app handles audio recording and playback independently, you can choose the format as needed.

Parameter Description

ParameterTypeRequiredDescription
conversationIConversationOptionYesConversation
msgBodyISendHQVoiceMessageOptionsYesMessage content to be sent
hooksIUploadHooksNoCallback hooks during upload
sendOptionsIUploadMessageOptionNoMessage configuration

Code Example

const conversation = {
conversationType: RongIMLib.ConversationType.PRIVATE,
targetId: ''
}
const msgBody = {
file, // File to be uploaded
user: { id: '', name: '', portraitUri: '', extra: '' }, // User information carried in the message (optional)
extra: '' // Transparent data carried in the message (optional)
}
const hooks = {
onProgress (progress) {}, // Upload progress listener (optional)
onComplete (fileInfo) { // Callback hook upon upload completion (optional)
console.log(fileInfo.url) // File storage URL
// To build a custom message, return new ABCMesssage('')
// ABCMesssage is defined via custom message implementation `const ABCMesssage = RongIMLib.registerMessageType(...)`
// If no return value is provided, SDK defaults to sending FileMessage
}
}
const options = {
contentDisposition: 'attachment' // How file links are displayed in browsers (only valid for aws, stc uploads) 'inline': preview in browser, 'attachment': direct download. If not provided, HTML files are previewed while others are downloaded directly.
// ... Other optional configurations
},

RongIMLib.sendHQVoiceMessage(
conversation,
msgBody,
hooks,
options
).then(({ code, data: message }) => {
if (code === 0) {
// Successfully sent
}
})

Sending Short Video Messages

tip

If your application uses the IMKit SDK on Android/iOS, you must use files encoded with H.264 + AAC, as IMKit's short video recording and playback only support this encoding combination.

Parameter Description

ParameterTypeRequiredDescription
conversationIConversationOptionYesConversation
msgBodyISendSightMessageOptionsYesMessage content to be sent
hooksIUploadHooksNoCallback hooks during upload
sendOptionsIUploadMessageOptionNoMessage configuration

Code Example

const conversation = {
conversationType: RongIMLib.ConversationType.PRIVATE,
targetId: ''
}
const msgBody = {
file, // File to upload
user: { id: '', name: '', portraitUri: '', extra: '' }, // User information carried in the message (optional)
extra: '', // Pass-through information carried in the message (optional)
duration: 10, // Duration
thumbnail: '' // Thumbnail
}
const hooks = {
onProgress (progress) {}, // Upload progress listener (optional)
onComplete (fileInfo) { // Callback hook when upload completes (optional)
console.log(fileInfo.url) // File storage URL
// To construct a custom message: return new ABCMesssage('')
// ABCMesssage definition via custom message implementation `const ABCMesssage = RongIMLib.registerMessageType(...)`
// If no return value is provided, SDK will send FileMessage by default
}
}
const options = {
contentDisposition: 'attachment' // File link display behavior in browsers (only valid for aws/stc uploads) 'inline': preview in browser, 'attachment': direct download. If not provided, HTML files will preview while others download directly.
// ... Other optional configurations
},

RongIMLib.sendSightMessage(
conversation,
msgBody,
hooks,
options
).then(({ code, data: message }) => {
if (code === 0) {
// Successfully sent
}
})

Sending Typing Status

To synchronize typing status to a specific conversation, call the sendTypingStatusMessage method.

Code Example

RongIMLib.sendTypingStatusMessage({
conversationType: RongIMLib.ConversationType.PRIVATE,
targetId: '<targetId>'
}, RongIMLib.MessageType.TEXT)

Why Resending Failed Messages May Cause Duplicates

This issue may occur when the sender has poor network connectivity.

Scenario

When User A sends a message to User B, the message successfully reaches the server and is delivered to recipient B. However, User A may not receive the server's acknowledgment due to network issues, causing User A to assume the message failed to send. If User A resends the message, User B will receive a duplicate.

Solution

Rong Cloud server does not handle message deduplication. Starting from SDK version 5.5.1, resending messages can include the original message's messageId. Applications can handle duplicates themselves.

Both sent and received messages contain a messageId field, which is a client-generated message ID. When resending messages from the Web client, include the failed message's messageId in the options parameter. Applications can filter duplicates by checking senderUserId and messageId before displaying messages.

Legacy Issues

  1. When recalling resent messages, only one message may be recalled while the other remains.
  2. When duplicate messages are received, even if filtered to display only one, the unread count will still show 2.

How to Implement Message Forwarding and Bulk Sending

Forwarding Messages: The IMLib SDK does not provide a dedicated forwarding interface. To implement message forwarding, applications can call the message sending API.

Bulk Sending: Bulk sending refers to sending messages to multiple users. More precisely, it means sending to multiple Target IDs?, where each Target ID may represent a user, group, or chatroom. The client SDK does not provide a direct API for bulk sending. Consider these approaches:

  • Have the application loop through the client's message sending API. Note that the client SDK limits message sending to 5 messages per second.
  • Integrate the IM Server API on your application server to handle bulk sending. The Send Private Message interface supports sending to multiple users in one call. You can also use the Send Group Message and Send Chatroom Message interfaces to send to multiple groups or chatrooms simultaneously.