> ## Documentation Index
> Fetch the complete documentation index at: https://cometchat-22654f5b-docs-agent-native-development.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Send Messages

> Send text, media, and custom messages to users and groups using the CometChat Android SDK.

<Accordion title="AI Integration Quick Reference">
  ```kotlin theme={null}
  // Text message
  val textMessage = TextMessage("UID", "Hello!", CometChatConstants.RECEIVER_TYPE_USER)
  CometChat.sendMessage(textMessage, object : CallbackListener<TextMessage>() {
      override fun onSuccess(msg: TextMessage) { }
      override fun onError(e: CometChatException) { }
  })

  // Media message (file upload)
  val mediaMessage = MediaMessage("UID", File("/path/to/file.jpg"),
      CometChatConstants.MESSAGE_TYPE_IMAGE, CometChatConstants.RECEIVER_TYPE_USER)
  CometChat.sendMediaMessage(mediaMessage, object : CallbackListener<MediaMessage>() {
      override fun onSuccess(msg: MediaMessage) { }
      override fun onError(e: CometChatException) { }
  })

  // Custom message
  val customData = JSONObject().apply { put("latitude", "19.07"); put("longitude", "72.87") }
  val customMessage = CustomMessage("UID", CometChatConstants.RECEIVER_TYPE_USER, "LOCATION", customData)
  CometChat.sendCustomMessage(customMessage, object : CallbackListener<CustomMessage>() {
      override fun onSuccess(msg: CustomMessage) { }
      override fun onError(e: CometChatException) { }
  })
  ```

  | Type | Method | Receiver Types |
  | - | - | - |
  | Text | `sendMessage()` | `RECEIVER_TYPE_USER`, `RECEIVER_TYPE_GROUP` |
  | Media | `sendMediaMessage()` | `RECEIVER_TYPE_USER`, `RECEIVER_TYPE_GROUP` |
  | Custom | `sendCustomMessage()` | `RECEIVER_TYPE_USER`, `RECEIVER_TYPE_GROUP` |
</Accordion>

CometChat supports three types of messages:

| Type | Method | Use Case |
| - | - | - |
| [Text](#text-message) | `sendMessage()` | Plain text messages |
| [Media](#media-message) | `sendMediaMessage()` | Images, videos, audio, files |
| [Custom](#custom-message) | `sendCustomMessage()` | Location, polls, or any JSON data |

You can also send [Interactive Messages](/sdk/android/interactive-messages) for forms, cards, and custom UI elements.

## Text Message

Send a text message using `sendMessage()` with a [`TextMessage`](/sdk/reference/messages#textmessage) object.

<Tabs>
  <Tab title="Java (User)">
    ```java theme={null}
    private String receiverID = "UID";
    private String messageText = "Hello CometChat!";
    private String receiverType = CometChatConstants.RECEIVER_TYPE_USER;

    TextMessage textMessage = new TextMessage(receiverID, messageText, receiverType);

    CometChat.sendMessage(textMessage, new CometChat.CallbackListener<TextMessage>() {
      @Override
      public void onSuccess(TextMessage textMessage) {
          Log.d(TAG, "Message sent successfully: " + textMessage.toString());
      }

      @Override
      public void onError(CometChatException e) {
          Log.d(TAG, "Message sending failed with exception: " + e.getMessage());
      }
    });
    ```
  </Tab>

  <Tab title="Kotlin (User)">
    ```kotlin theme={null}
    private val receiverID = "UID"
    private val messageText = "Hello CometChat!"
    private val receiverType = CometChatConstants.RECEIVER_TYPE_USER

    val textMessage = TextMessage(receiverID, messageText, receiverType)

    CometChat.sendMessage(textMessage, object : CallbackListener<TextMessage>() {
      override fun onSuccess(textMessage: TextMessage) {
          Log.d(TAG, "Message sent successfully: $textMessage")
      }

      override fun onError(e: CometChatException) {
          Log.d(TAG, "Message sending failed with exception: " + e.message)
      }
    })
    ```
  </Tab>

  <Tab title="Java (Group)">
    ```java theme={null}
    private String receiverID = "GUID";
    private String messageText = "Hello CometChat!";
    private String receiverType = CometChatConstants.RECEIVER_TYPE_GROUP;

    TextMessage textMessage = new TextMessage(receiverID, messageText, receiverType);

    CometChat.sendMessage(textMessage, new CometChat.CallbackListener<TextMessage>() {
      @Override
      public void onSuccess(TextMessage textMessage) {
          Log.d(TAG, "Message sent successfully: " + textMessage.toString());
      }

      @Override
      public void onError(CometChatException e) {
          Log.d(TAG, "Message sending failed with exception: " + e.getMessage());
      }
    });
    ```
  </Tab>

  <Tab title="Kotlin (Group)">
    ```kotlin theme={null}
    private val receiverID = "GUID"
    private val messageText = "Hello CometChat!"
    private val receiverType = CometChatConstants.RECEIVER_TYPE_GROUP

    val textMessage = TextMessage(receiverID, messageText, receiverType)
    CometChat.sendMessage(textMessage, object : CallbackListener<TextMessage>() {
      override fun onSuccess(textMessage: TextMessage) {
          Log.d(TAG, "Message sent successfully: $textMessage")
      }

      override fun onError(e: CometChatException) {
          Log.d(TAG, "Message sending failed with exception: " + e.message)
      }
    })
    ```
  </Tab>
</Tabs>

The `TextMessage` class constructor takes the following parameters:

| Parameter | Description | Required |
| - | - | - |
| `receiverID` | `UID` of the user or `GUID` of the group receiving the message | Yes |
| `messageText` | The text message content | Yes |
| `receiverType` | `CometChatConstants.RECEIVER_TYPE_USER` or `RECEIVER_TYPE_GROUP` | Yes |

On success, `sendMessage()` returns a [`TextMessage`](/sdk/reference/messages#textmessage) object containing all information about the sent message.

### Add Metadata

Attach custom JSON data to the message:

<Tabs>
  <Tab title="Java">
    ```java theme={null}
    JSONObject metadata = new JSONObject();
    metadata.put("latitude", "50.6192171633316");
    metadata.put("longitude", "-72.68182268750002");
    textMessage.setMetadata(metadata);
    ```
  </Tab>

  <Tab title="Kotlin">
    ```kotlin theme={null}
    val metadata = JSONObject()
    metadata.put("latitude", "50.6192171633316")
    metadata.put("longitude", "-72.68182268750002")
    textMessage.setMetadata(metadata)
    ```
  </Tab>
</Tabs>

### Add Tags

Tag messages for easy filtering later:

<Tabs>
  <Tab title="Java">
    ```java theme={null}
    List<String> tags = new ArrayList<>();
    tags.add("pinned");
    textMessage.setTags(tags);
    ```
  </Tab>

  <Tab title="Kotlin">
    ```kotlin theme={null}
    val tags: MutableList<String> = ArrayList()
    tags.add("pinned")
    textMessage.setTags(tags)
    ```
  </Tab>
</Tabs>

### Quote a Message

Reply to a specific message by setting its ID:

<Tabs>
  <Tab title="Java">
    ```java theme={null}
    textMessage.setQuotedMessageId(10);
    ```
  </Tab>

  <Tab title="Kotlin">
    ```kotlin theme={null}
    textMessage.quotedMessageId = 10
    ```
  </Tab>
</Tabs>

## Media Message

Send images, videos, audio, or files using `sendMediaMessage()`.

There are two ways to send media messages:

1. **Upload a file** — Pass a `File` object and CometChat uploads it automatically
2. **Send a URL** — Provide a URL to media hosted on your server or cloud storage

### Add Metadata

<Tabs>
  <Tab title="Java">
    ```java theme={null}
    JSONObject metadata = new JSONObject();
    metadata.put("latitude", "50.6192171633316");
    metadata.put("longitude", "-72.68182268750002");
    mediaMessage.setMetadata(metadata);
    ```
  </Tab>

  <Tab title="Kotlin">
    ```kotlin theme={null}
    val metadata = JSONObject()
    metadata.put("latitude", "50.6192171633316")
    metadata.put("longitude", "-72.68182268750002")
    mediaMessage.setMetadata(metadata)
    ```
  </Tab>
</Tabs>

### Add Caption

Add text along with the media:

<Tabs>
  <Tab title="Java">
    ```java theme={null}
    mediaMessage.setCaption("Message Caption");
    ```
  </Tab>

  <Tab title="Kotlin">
    ```kotlin theme={null}
    mediaMessage.setCaption("Message Caption")
    ```
  </Tab>
</Tabs>

### Add Tags

<Tabs>
  <Tab title="Java">
    ```java theme={null}
    List<String> tags = new ArrayList<>();
    tags.add("pinned");
    mediaMessage.setTags(tags);
    ```
  </Tab>

  <Tab title="Kotlin">
    ```kotlin theme={null}
    val tags: MutableList<String> = ArrayList()
    tags.add("pinned")
    mediaMessage.setTags(tags)
    ```
  </Tab>
</Tabs>

### Upload a File

Pass a `File` object directly. CometChat uploads it to its servers and returns the URL in the success response.

<Tabs>
  <Tab title="Java (User)">
    ```java theme={null}
    private String receiverID = "UID";
    private String messageType = CometChatConstants.MESSAGE_TYPE_IMAGE;
    private String receiverType = CometChatConstants.RECEIVER_TYPE_USER;
    private String filePath = "/storage/emulated/0/Download/CometChat.jpg";

    MediaMessage mediaMessage = new MediaMessage(receiverID, new File(filePath), messageType, receiverType);

    CometChat.sendMediaMessage(mediaMessage, new CometChat.CallbackListener<MediaMessage>() {
      @Override
      public void onSuccess(MediaMessage mediaMessage) {
          Log.d(TAG, "Media message sent successfully: " + mediaMessage.toString());
      }

      @Override
      public void onError(CometChatException e) {
          Log.d(TAG, "Media message sending failed with exception: " + e.getMessage());
      }
    });
    ```
  </Tab>

  <Tab title="Kotlin (User)">
    ```kotlin theme={null}
    private val receiverID = "UID"
    private val messageType = CometChatConstants.MESSAGE_TYPE_IMAGE
    private val receiverType = CometChatConstants.RECEIVER_TYPE_USER
    private val filePath = "/storage/emulated/0/Download/CometChat.jpg"

    val mediaMessage = MediaMessage(receiverID, File(filePath), messageType, receiverType)
    CometChat.sendMediaMessage(mediaMessage, object : CallbackListener<MediaMessage>() {
      override fun onSuccess(mediaMessage: MediaMessage) {
          Log.d(TAG, "Media message sent successfully: " + mediaMessage.toString())
      }

      override fun onError(e: CometChatException) {
          Log.d(TAG, "Media message sending failed with exception: " + e.message)
      }
    })
    ```
  </Tab>

  <Tab title="Java (Group)">
    ```java theme={null}
    private String receiverID = "GUID";
    private String messageType = CometChatConstants.MESSAGE_TYPE_IMAGE;
    private String receiverType = CometChatConstants.RECEIVER_TYPE_GROUP;
    private String filePath = "/storage/emulated/0/Download/CometChat.jpg";

    MediaMessage mediaMessage = new MediaMessage(receiverID, new File(filePath), messageType, receiverType);

    CometChat.sendMediaMessage(mediaMessage, new CometChat.CallbackListener<MediaMessage>() {
      @Override
      public void onSuccess(MediaMessage mediaMessage) {
          Log.d(TAG, "Media message sent successfully: " + mediaMessage.toString());
      }

      @Override
      public void onError(CometChatException e) {
          Log.d(TAG, "Media message sending failed with exception: " + e.getMessage());
      }
    });
    ```
  </Tab>

  <Tab title="Kotlin (Group)">
    ```kotlin theme={null}
    private val receiverID = "GUID"
    private val messageType = CometChatConstants.MESSAGE_TYPE_IMAGE
    private val receiverType = CometChatConstants.RECEIVER_TYPE_GROUP
    private val filePath = "/storage/emulated/0/Download/CometChat.jpg"

    val mediaMessage = MediaMessage(receiverID, File(filePath), messageType, receiverType)
    CometChat.sendMediaMessage(mediaMessage, object : CallbackListener<MediaMessage>() {
      override fun onSuccess(mediaMessage: MediaMessage) {
          Log.d(TAG, "Media message sent successfully: " + mediaMessage.toString())
      }

      override fun onError(e: CometChatException) {
          Log.d(TAG, "Media message sending failed with exception: " + e.message)
      }
    })
    ```
  </Tab>
</Tabs>

The `MediaMessage` class constructor takes the following parameters:

| Parameter | Description | Required |
| - | - | - |
| `receiverId` | The UID or GUID of the recipient | Yes |
| `file` | The `File` object to upload | Yes |
| `messageType` | `MESSAGE_TYPE_IMAGE`, `MESSAGE_TYPE_VIDEO`, `MESSAGE_TYPE_AUDIO`, or `MESSAGE_TYPE_FILE` | Yes |
| `receiverType` | `RECEIVER_TYPE_USER` or `RECEIVER_TYPE_GROUP` | Yes |

### Send a URL

Send media hosted on your server or cloud storage using the [`Attachment`](/sdk/reference/auxiliary#attachment) class:

<Tabs>
  <Tab title="Java (User)">
    ```java theme={null}
    String receiverId = "recipient_UID";

    MediaMessage mediaMessage = new MediaMessage(receiverId, CometChatConstants.MESSAGE_TYPE_IMAGE, CometChatConstants.RECEIVER_TYPE_USER);

    Attachment attachment = new Attachment();
    attachment.setFileName("test");
    attachment.setFileExtension("png");
    attachment.setFileUrl("https://pngimg.com/uploads/mario/mario_PNG125.png");

    mediaMessage.setAttachment(attachment);

    CometChat.sendMediaMessage(mediaMessage, new CometChat.CallbackListener<MediaMessage>() {
      @Override
      public void onSuccess(MediaMessage mediaMessage1) {
          Log.i(TAG, "onSuccess");
      }

      @Override
      public void onError(CometChatException e) {
          Log.e(TAG, e.getMessage());
      }
    });
    ```
  </Tab>

  <Tab title="Kotlin (User)">
    ```kotlin theme={null}
    val receiverId = "recipient_UID"

    val mediaMessage = MediaMessage(receiverId, CometChatConstants.MESSAGE_TYPE_IMAGE, CometChatConstants.RECEIVER_TYPE_USER)

    val attachment = Attachment()
    attachment.fileName = "test"
    attachment.fileExtension = "png"
    attachment.fileUrl = "https://pngimg.com/uploads/mario/mario_PNG125.png"

    mediaMessage.attachment = attachment

    CometChat.sendMediaMessage(mediaMessage, object : CallbackListener<MediaMessage?>() {
      override fun onSuccess(mediaMessage1: MediaMessage?) {
          Log.i(TAG, "onSuccess")
      }

      override fun onError(e: CometChatException) {
          Log.e(TAG, e.message!!)
      }
    })
    ```
  </Tab>

  <Tab title="Java (Group)">
    ```java theme={null}
    String receiverId = "recipient_GUID";

    MediaMessage mediaMessage = new MediaMessage(receiverId, CometChatConstants.MESSAGE_TYPE_IMAGE, CometChatConstants.RECEIVER_TYPE_GROUP);

    Attachment attachment = new Attachment();
    attachment.setFileName("test");
    attachment.setFileExtension("png");
    attachment.setFileUrl("https://pngimg.com/uploads/mario/mario_PNG125.png");

    mediaMessage.setAttachment(attachment);

    CometChat.sendMediaMessage(mediaMessage, new CometChat.CallbackListener<MediaMessage>() {
      @Override
      public void onSuccess(MediaMessage mediaMessage1) {
          Log.i(TAG, "onSuccess");
      }

      @Override
      public void onError(CometChatException e) {
          Log.e(TAG, e.getMessage());
      }
    });
    ```
  </Tab>

  <Tab title="Kotlin (Group)">
    ```kotlin theme={null}
    val receiverId = "recipient_GUID"

    val mediaMessage = MediaMessage(receiverId, CometChatConstants.MESSAGE_TYPE_IMAGE, CometChatConstants.RECEIVER_TYPE_GROUP)

    val attachment = Attachment()
    attachment.fileName = "test"
    attachment.fileExtension = "png"
    attachment.fileUrl = "https://pngimg.com/uploads/mario/mario_PNG125.png"

    mediaMessage.attachment = attachment

    CometChat.sendMediaMessage(mediaMessage, object : CallbackListener<MediaMessage?>() {
      override fun onSuccess(mediaMessage1: MediaMessage?) {
          Log.i(TAG, "onSuccess")
      }

      override fun onError(e: CometChatException) {
          Log.e(TAG, e.message!!)
      }
    })
    ```
  </Tab>
</Tabs>

On success, `sendMediaMessage()` returns a [`MediaMessage`](/sdk/reference/messages#mediamessage) object.

## Multiple Attachments

Starting version 3.0.9, the SDK supports sending multiple attachments in a single media message.

### Upload Multiple Files

<Tabs>
  <Tab title="Java (User)">
    ```java theme={null}
    String receiverId = "cometchat-uid-1";

    List<File> files = new ArrayList<File>();
    files.add(new File("/storage/emulated/0/Download/1.jpg"));
    files.add(new File("/storage/emulated/0/Download/2.jpg"));
    files.add(new File("/storage/emulated/0/Download/3.jpg"));

    MediaMessage mediaMessage = new MediaMessage(receiverId, files, fileType, CometChatConstants.RECEIVER_TYPE_USER);

    CometChat.sendMediaMessage(mediaMessage, new CometChat.CallbackListener<MediaMessage>() {
      @Override
      public void onSuccess(MediaMessage mediaMessage) {
          Log.d(TAG, "Message Sent Successfully")
      }

      @Override
      public void onError(CometChatException e) {
          Log.d(TAG, "Message Sending Failed with exception : " + e.getMessage());
      }
    });
    ```
  </Tab>

  <Tab title="Kotlin (User)">
    ```kotlin theme={null}
    val receiverId = "cometchat-uid-1"
    val files: MutableList<File> = ArrayList()
    files.add(File("/storage/emulated/0/Download/1.jpg"))
    files.add(File("/storage/emulated/0/Download/2.jpg"))
    files.add(File("/storage/emulated/0/Download/3.jpg"))

    val mediaMessage = MediaMessage(receiverId, files, fileType, CometChatConstants.RECEIVER_TYPE_USER)

    CometChat.sendMediaMessage(mediaMessage, object : CallbackListener<MediaMessage?>() {
      override fun onSuccess(mediaMessage: MediaMessage?) {
          Log.d(TAG, "Message Sent Successfully")
      }

      override fun onError(e: CometChatException) {
          Log.d(TAG, "Message Sending Failed with exception : " + e.message)
      }
    })
    ```
  </Tab>

  <Tab title="Java (Group)">
    ```java theme={null}
    String groupId = "cometchat-guid-1";

    List<File> files = new ArrayList<File>();
    files.add(new File("/storage/emulated/0/Download/1.jpg"));
    files.add(new File("/storage/emulated/0/Download/2.jpg"));
    files.add(new File("/storage/emulated/0/Download/3.jpg"));

    MediaMessage mediaMessage = new MediaMessage(groupId, files, fileType, CometChatConstants.RECEIVER_TYPE_GROUP);

    CometChat.sendMediaMessage(mediaMessage, new CometChat.CallbackListener<MediaMessage>() {
      @Override
      public void onSuccess(MediaMessage mediaMessage) {
          Log.d(TAG, "Message Sent Successfully")
      }

      @Override
      public void onError(CometChatException e) {
          Log.d(TAG, "Message Sending Failed with exception : " + e.getMessage());
      }
    });
    ```
  </Tab>

  <Tab title="Kotlin (Group)">
    ```kotlin theme={null}
    val groupId = "cometchat-guid-1"

    val files: MutableList<File> = ArrayList()
    files.add(File("/storage/emulated/0/Download/1.jpg"))
    files.add(File("/storage/emulated/0/Download/2.jpg"))
    files.add(File("/storage/emulated/0/Download/3.jpg"))

    val mediaMessage = MediaMessage(groupId, files, fileType, CometChatConstants.RECEIVER_TYPE_GROUP)

    CometChat.sendMediaMessage(mediaMessage, object : CallbackListener<MediaMessage?>() {
      override fun onSuccess(mediaMessage: MediaMessage?) {
          Log.d(TAG, "Message Sent Successfully")
      }

      override fun onError(e: CometChatException) {
          Log.d(TAG, "Message Sending Failed with exception : " + e.message)
      }
    })
    ```
  </Tab>
</Tabs>

The `MediaMessage` class constructor takes the following parameters:

| Parameter | Description | Required |
| - | - | - |
| `receiverId` | The `UID` or `GUID` of the recipient | Yes |
| `files` | A `List<File>` of files to upload | Yes |
| `messageType` | `MESSAGE_TYPE_IMAGE`, `MESSAGE_TYPE_VIDEO`, `MESSAGE_TYPE_AUDIO`, or `MESSAGE_TYPE_FILE` | Yes |
| `receiverType` | `RECEIVER_TYPE_USER` or `RECEIVER_TYPE_GROUP` | Yes |

### Send Multiple URLs

<Tabs>
  <Tab title="Java (User)">
    ```java theme={null}
    String receiverId = "cometchat-uid-1";

    MediaMessage mediaMessage = new MediaMessage(receiverId, CometChatConstants.MESSAGE_TYPE_IMAGE, CometChatConstants.RECEIVER_TYPE_USER);

    List<Attachment> attachments = new ArrayList<>();
    for (int i = 0; i < 5; i++) {
        Attachment attachment = new Attachment();
        attachment.setFileName("test");
        attachment.setFileExtension("png");
        attachment.setFileUrl("https://pngimg.com/uploads/mario/mario_PNG125.png");
        attachment.setFileMimeType("image/png");
        attachments.add(attachment);
    }

    mediaMessage.setAttachments(attachments);

    CometChat.sendMediaMessage(mediaMessage, new CometChat.CallbackListener<MediaMessage>() {
        @Override
        public void onSuccess(MediaMessage mediaMessage) {
            Log.d(TAG, "Message Sent Successfully")
        }

        @Override
        public void onError(CometChatException e) {
            Log.d(TAG, "Message Sending Failed with exception : " + e.getMessage());
        }
    });
    ```
  </Tab>

  <Tab title="Kotlin (User)">
    ```kotlin theme={null}
    val receiverId = "cometchat-uid-1"
    val mediaMessage = MediaMessage(receiverId, CometChatConstants.MESSAGE_TYPE_IMAGE, CometChatConstants.RECEIVER_TYPE_USER)

    val attachments: MutableList<Attachment> = ArrayList()
    for (i in 0..4) {
        val attachment = Attachment()
        attachment.fileName = "test"
        attachment.fileExtension = "png"
        attachment.fileUrl = "https://pngimg.com/uploads/mario/mario_PNG125.png"
        attachment.fileMimeType = "image/png"
        attachments.add(attachment)
    }

    mediaMessage.attachments = attachments

    CometChat.sendMediaMessage(mediaMessage, object : CallbackListener<MediaMessage?>() {
        override fun onSuccess(mediaMessage: MediaMessage?) {
            Log.d(TAG, "Message Sent Successfully")
        }

        override fun onError(e: CometChatException) {
            Log.d(TAG, "Message Sending Failed with exception : " + e.message)
        }
    })
    ```
  </Tab>

  <Tab title="Java (Group)">
    ```java theme={null}
    String groupId = "cometchat-guid-1";

    MediaMessage mediaMessage = new MediaMessage(groupId, CometChatConstants.MESSAGE_TYPE_IMAGE, CometChatConstants.RECEIVER_TYPE_GROUP);

    List<Attachment> attachments = new ArrayList<>();
    for (int i = 0; i < 5; i++) {
        Attachment attachment = new Attachment();
        attachment.setFileName("test");
        attachment.setFileExtension("png");
        attachment.setFileUrl("https://pngimg.com/uploads/mario/mario_PNG125.png");
        attachment.setFileMimeType("image/png");
        attachments.add(attachment);
    }

    mediaMessage.setAttachments(attachments);

    CometChat.sendMediaMessage(mediaMessage, new CometChat.CallbackListener<MediaMessage>() {
        @Override
        public void onSuccess(MediaMessage mediaMessage) {
            Log.d(TAG, "Message Sent Successfully")
        }

        @Override
        public void onError(CometChatException e) {
            Log.d(TAG, "Message Sending Failed with exception : " + e.getMessage());
        }
    });
    ```
  </Tab>

  <Tab title="Kotlin (Group)">
    ```kotlin theme={null}
    val groupId = "cometchat-guid-1"
    val mediaMessage = MediaMessage(groupId, CometChatConstants.MESSAGE_TYPE_IMAGE, CometChatConstants.RECEIVER_TYPE_GROUP)

    val attachments: MutableList<Attachment> = ArrayList()
    for (i in 0..4) {
        val attachment = Attachment()
        attachment.fileName = "test"
        attachment.fileExtension = "png"
        attachment.fileUrl = "https://pngimg.com/uploads/mario/mario_PNG125.png"
        attachment.fileMimeType = "image/png"
        attachments.add(attachment)
    }

    mediaMessage.attachments = attachments

    CometChat.sendMediaMessage(mediaMessage, object : CallbackListener<MediaMessage?>() {
        override fun onSuccess(mediaMessage: MediaMessage?) {
            Log.d(TAG, "Message Sent Successfully")
        }

        override fun onError(e: CometChatException) {
            Log.d(TAG, "Message Sending Failed with exception : " + e.message)
        }
    })
    ```
  </Tab>
</Tabs>

When a media message is sent successfully, the response will include a [`MediaMessage`](/sdk/reference/messages#mediamessage) object which includes all information related to the sent message.

You can use the `setMetadata()`, `setCaption()` & `setTags()` methods to add metadata, caption and tags in the same way as a single attachment.

## Custom Message

Send custom data that doesn't fit text or media using `sendCustomMessage()`.

<Tabs>
  <Tab title="Java">
    ```java theme={null}
    CustomMessage customMessage = new CustomMessage(receiverId, receiverType, customType, customData)
    ```
  </Tab>

  <Tab title="Kotlin">
    ```kotlin theme={null}
    val customMessage = CustomMessage(receiverId, receiverType, customType, customData)
    ```
  </Tab>
</Tabs>

| Parameter | Description | Required |
| - | - | - |
| `receiverId` | UID of the user or GUID of the group | Yes |
| `receiverType` | `RECEIVER_TYPE_USER` or `RECEIVER_TYPE_GROUP` | Yes |
| `customType` | Developer-defined type string (e.g., `"LOCATION"`, `"POLL"`) | Yes |
| `customData` | The payload as a `JSONObject` | Yes |

You can also set a subtype using `setSubtype()` to further classify the custom message.

### Add Tags

<Tabs>
  <Tab title="Java">
    ```java theme={null}
    List<String> tags = new ArrayList<>();
    tags.add("pinned");
    customMessage.setTags(tags);
    ```
  </Tab>

  <Tab title="Kotlin">
    ```kotlin theme={null}
    val tags: MutableList<String> = ArrayList()
    tags.add("pinned")
    customMessage.setTags(tags)
    ```
  </Tab>
</Tabs>

Once the message object is ready, call `sendCustomMessage()`.

<Tabs>
  <Tab title="Java (User)">
    ```java theme={null}
    private String UID = "UID";
    private String customType = "LOCATION";

    JSONObject customData = new JSONObject();
    customData.put("latitude", "19.0760");
    customData.put("longitude", "72.8777");

    CustomMessage customMessage = new CustomMessage(UID, CometChatConstants.RECEIVER_TYPE_USER, customType, customData);

    CometChat.sendCustomMessage(customMessage, new CometChat.CallbackListener<CustomMessage>() {
      @Override
      public void onSuccess(CustomMessage customMessage) {
          Log.d(TAG, customMessage.toString());
      }

      @Override
      public void onError(CometChatException e) {
          Log.d(TAG, e.getMessage());
      }
    });
    ```
  </Tab>

  <Tab title="Kotlin (User)">
    ```kotlin theme={null}
    private val UID = "UID"
    private val customType = "LOCATION"

    val customData = JSONObject()
    customData.put("latitude", "19.0760")
    customData.put("longitude", "72.8777")
    val customMessage = CustomMessage(UID, CometChatConstants.RECEIVER_TYPE_USER, customType, customData)

    CometChat.sendCustomMessage(customMessage, object : CallbackListener<CustomMessage>() {
      override fun onSuccess(customMessage: CustomMessage) {
          Log.d(TAG, customMessage.toString())
      }

      override fun onError(e: CometChatException) {
          Log.d(TAG, e.message!!)
      }
    })
    ```
  </Tab>

  <Tab title="Java (Group)">
    ```java theme={null}
    private String GUID = "GUID";
    private String customType = "LOCATION";

    JSONObject customData = new JSONObject();
    customData.put("latitude", "19.0760");
    customData.put("longitude", "72.8777");

    CustomMessage customMessage = new CustomMessage(GUID, CometChatConstants.RECEIVER_TYPE_GROUP, customType, customData);

    CometChat.sendCustomMessage(customMessage, new CometChat.CallbackListener<CustomMessage>() {
      @Override
      public void onSuccess(CustomMessage customMessage) {
          Log.d(TAG, customMessage.toString());
      }

      @Override
      public void onError(CometChatException e) {
          Log.d(TAG, e.getMessage());
      }
    });
    ```
  </Tab>

  <Tab title="Kotlin (Group)">
    ```kotlin theme={null}
    private val GUID = "GUID"
    private val customType = "LOCATION"

    val customData = JSONObject()
    customData.put("latitude", "19.0760")
    customData.put("longitude", "72.8777")
    val customMessage = CustomMessage(GUID, CometChatConstants.RECEIVER_TYPE_GROUP, customType, customData)

    CometChat.sendCustomMessage(customMessage, object : CallbackListener<CustomMessage>() {
      override fun onSuccess(customMessage: CustomMessage) {
          Log.d(TAG, customMessage.toString())
      }

      override fun onError(e: CometChatException) {
          Log.d(TAG, e.message!!)
      }
    })
    ```
  </Tab>
</Tabs>

On success, `sendCustomMessage()` returns a [`CustomMessage`](/sdk/reference/messages#custommessage) object.

### Control Conversation Update

By default, a custom message updates the conversation's last message. To prevent this:

<Tabs>
  <Tab title="Java (User)">
    ```java theme={null}
    private String UID = "UID";
    private String customType = "LOCATION";

    JSONObject customData = new JSONObject();
    customData.put("latitude", "19.0760");
    customData.put("longitude", "72.8777");

    CustomMessage customMessage = new CustomMessage(UID, CometChatConstants.RECEIVER_TYPE_USER, customType, customData);
    customMessage.shouldUpdateConversation(false);

    CometChat.sendCustomMessage(customMessage, new CometChat.CallbackListener<CustomMessage>() {
      @Override
      public void onSuccess(CustomMessage customMessage) {
          Log.d(TAG, customMessage.toString());
      }

      @Override
      public void onError(CometChatException e) {
          Log.d(TAG, e.getMessage());
      }
    });
    ```
  </Tab>

  <Tab title="Kotlin (User)">
    ```kotlin theme={null}
    private val UID = "UID"
    private val customType = "LOCATION"

    val customData = JSONObject()
    customData.put("latitude", "19.0760")
    customData.put("longitude", "72.8777")

    val customMessage = CustomMessage(UID, CometChatConstants.RECEIVER_TYPE_USER, customType, customData)
    customMessage.shouldUpdateConversation(false)

    CometChat.sendCustomMessage(customMessage, object : CallbackListener<CustomMessage>() {
      override fun onSuccess(customMessage: CustomMessage) {
          Log.d(TAG, customMessage.toString())
      }

      override fun onError(e: CometChatException) {
          Log.d(TAG, e.message!!)
      }
    })
    ```
  </Tab>

  <Tab title="Java (Group)">
    ```java theme={null}
    private String GUID = "GUID";
    private String customType = "LOCATION";

    JSONObject customData = new JSONObject();
    customData.put("latitude", "19.0760");
    customData.put("longitude", "72.8777");

    CustomMessage customMessage = new CustomMessage(GUID, CometChatConstants.RECEIVER_TYPE_GROUP, customType, customData);
    customMessage.shouldUpdateConversation(false);

    CometChat.sendCustomMessage(customMessage, new CometChat.CallbackListener<CustomMessage>() {
      @Override
      public void onSuccess(CustomMessage customMessage) {
          Log.d(TAG, customMessage.toString());
      }

      @Override
      public void onError(CometChatException e) {
          Log.d(TAG, e.getMessage());
      }
    });
    ```
  </Tab>

  <Tab title="Kotlin (Group)">
    ```kotlin theme={null}
    private val GUID = "GUID"
    private val customType = "LOCATION"

    val customData = JSONObject()
    customData.put("latitude", "19.0760")
    customData.put("longitude", "72.8777")

    val customMessage = CustomMessage(GUID, CometChatConstants.RECEIVER_TYPE_GROUP, customType, customData)
    customMessage.shouldUpdateConversation(false)

    CometChat.sendCustomMessage(customMessage, object : CallbackListener<CustomMessage>() {
      override fun onSuccess(customMessage: CustomMessage) {
          Log.d(TAG, customMessage.toString())
      }

      override fun onError(e: CometChatException) {
          Log.d(TAG, e.message!!)
      }
    })
    ```
  </Tab>
</Tabs>

### Custom Notification Text

Set custom text for push, email, and SMS notifications:

<Tabs>
  <Tab title="Java (User)">
    ```java theme={null}
    private String UID = "UID";
    private String customType = "LOCATION";

    JSONObject customData = new JSONObject();
    customData.put("latitude", "19.0760");
    customData.put("longitude", "72.8777");

    CustomMessage customMessage = new CustomMessage(UID, CometChatConstants.RECEIVER_TYPE_USER, customType, customData);
    customMessage.setConversationText("Custom Notification Body");

    CometChat.sendCustomMessage(customMessage, new CometChat.CallbackListener<CustomMessage>() {
      @Override
      public void onSuccess(CustomMessage customMessage) {
          Log.d(TAG, customMessage.toString());
      }

      @Override
      public void onError(CometChatException e) {
          Log.d(TAG, e.getMessage());
      }
    });
    ```
  </Tab>

  <Tab title="Kotlin (User)">
    ```kotlin theme={null}
    private val UID = "UID"
    private val customType = "LOCATION"

    val customData = JSONObject()
    customData.put("latitude", "19.0760")
    customData.put("longitude", "72.8777")

    val customMessage = CustomMessage(UID, CometChatConstants.RECEIVER_TYPE_USER, customType, customData)
    customMessage.setConversationText("Custom Notification Body")

    CometChat.sendCustomMessage(customMessage, object : CallbackListener<CustomMessage>() {
      override fun onSuccess(customMessage: CustomMessage) {
          Log.d(TAG, customMessage.toString())
      }

      override fun onError(e: CometChatException) {
          Log.d(TAG, e.message!!)
      }
    })
    ```
  </Tab>

  <Tab title="Java (Group)">
    ```java theme={null}
    private String GUID = "GUID";
    private String customType = "LOCATION";

    JSONObject customData = new JSONObject();
    customData.put("latitude", "19.0760");
    customData.put("longitude", "72.8777");

    CustomMessage customMessage = new CustomMessage(GUID, CometChatConstants.RECEIVER_TYPE_GROUP, customType, customData);
    customMessage.setConversationText("Custom Notification Body");

    CometChat.sendCustomMessage(customMessage, new CometChat.CallbackListener<CustomMessage>() {
      @Override
      public void onSuccess(CustomMessage customMessage) {
          Log.d(TAG, customMessage.toString());
      }

      @Override
      public void onError(CometChatException e) {
          Log.d(TAG, e.getMessage());
      }
    });
    ```
  </Tab>

  <Tab title="Kotlin (Group)">
    ```kotlin theme={null}
    private val GUID = "GUID"
    private val customType = "LOCATION"

    val customData = JSONObject()
    customData.put("latitude", "19.0760")
    customData.put("longitude", "72.8777")

    val customMessage = CustomMessage(GUID, CometChatConstants.RECEIVER_TYPE_GROUP, customType, customData)
    customMessage.setConversationText("Custom Notification Body")

    CometChat.sendCustomMessage(customMessage, object : CallbackListener<CustomMessage>() {
      override fun onSuccess(customMessage: CustomMessage) {
          Log.d(TAG, customMessage.toString())
      }

      override fun onError(e: CometChatException) {
          Log.d(TAG, e.message!!)
      }
    })
    ```
  </Tab>
</Tabs>

<Note>
  It is also possible to send interactive messages from CometChat, to know more [click here](/sdk/android/interactive-messages)
</Note>

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Receive Messages" icon="envelope" href="/sdk/android/receive-messages">
    Listen for incoming messages in real time
  </Card>

  <Card title="Edit Message" icon="pen" href="/sdk/android/edit-message">
    Modify sent messages after delivery
  </Card>

  <Card title="Delete Message" icon="trash" href="/sdk/android/delete-message">
    Remove messages from conversations
  </Card>

  <Card title="Interactive Messages" icon="square-check" href="/sdk/android/interactive-messages">
    Send messages with embedded forms and buttons
  </Card>
</CardGroup>

## Message Payload Structure

<Accordion title="BaseMessage Object">
  The `BaseMessage` object returned by SDK methods contains the following fields. `TextMessage`, `MediaMessage`, and `CustomMessage` extend this base structure with additional type-specific fields.

  | Parameter | Type | Description |
  | - | - | - |
  | `id` | long | Unique message identifier |
  | `muid` | String | Developer-defined message ID for deduplication |
  | `sender` | [User](#user-object) | User who sent the message |
  | `receiver` | AppEntity | Message receiver ([User](#user-object) or [Group](#group-object)) |
  | `receiverUid` | String | Receiver's unique identifier |
  | `type` | String | Message type. Values: `"text"`, `"image"`, `"video"`, `"audio"`, `"file"`, `"custom"` |
  | `receiverType` | String | Type of receiver. Values: `"user"`, `"group"` |
  | `category` | String | Message category. Values: `"message"`, `"action"`, `"call"`, `"custom"` |
  | `sentAt` | long | Unix timestamp when message was sent |
  | `deliveredAt` | long | Unix timestamp when message was delivered |
  | `readAt` | long | Unix timestamp when message was read |
  | `metadata` | JSONObject | Custom message metadata set by developer |
  | `readByMeAt` | long | Unix timestamp when logged-in user read the message |
  | `deliveredToMeAt` | long | Unix timestamp when message was delivered to logged-in user |
  | `deletedAt` | long | Unix timestamp when message was deleted (0 if not deleted) |
  | `editedAt` | long | Unix timestamp when message was edited (0 if not edited) |
  | `deletedBy` | String | UID of user who deleted the message (null if not deleted) |
  | `editedBy` | String | UID of user who edited the message (null if not edited) |
  | `updatedAt` | long | Unix timestamp of last message update |
  | `conversationId` | String | Associated conversation identifier |
  | `parentMessageId` | long | Parent message ID for threaded messages (0 if not a reply) |
  | `replyCount` | int | Number of replies in thread |
  | `unreadRepliesCount` | int | Number of unread replies in thread |
  | `mentionedUsers` | Array\<[User](#user-object)> | List of users mentioned in the message |
  | `hasMentionedMe` | boolean | Whether the logged-in user is mentioned |
  | `reactions` | Array\<[ReactionCount](#reactioncount-object)> | List of reaction counts on the message |
  | `rawMessage` | JSONObject | Raw JSON message data |
  | `quotedMessageId` | long | ID of the quoted message (0 if not quoting) |
  | `quotedMessage` | BaseMessage | The quoted message object (null if not quoting) |

  **Sample BaseMessage Object:**

  ```json theme={null}
  {
    "id": 12345,
    "muid": "msg_abc123",
    "sender": {
      "uid": "user_123",
      "name": "John Doe",
      "avatar": "https://example.com/avatar.png",
      "status": "online",
      "role": "default",
      "lastActiveAt": 1699900000
    },
    "receiver": {
      "uid": "user_456",
      "name": "Jane Smith",
      "avatar": "https://example.com/avatar2.png"
    },
    "receiverUid": "user_456",
    "type": "text",
    "receiverType": "user",
    "category": "message",
    "sentAt": 1699900000,
    "deliveredAt": 1699900001,
    "readAt": 1699900002,
    "metadata": {
      "priority": "high",
      "customField": "value"
    },
    "readByMeAt": 1699900002,
    "deliveredToMeAt": 1699900001,
    "deletedAt": 0,
    "editedAt": 0,
    "deletedBy": null,
    "editedBy": null,
    "updatedAt": 1699900000,
    "conversationId": "user_123_user_456",
    "parentMessageId": 0,
    "replyCount": 5,
    "unreadRepliesCount": 2,
    "mentionedUsers": [],
    "hasMentionedMe": false,
    "reactions": [
      {
        "reaction": "👍",
        "count": 3,
        "reactedByMe": true
      }
    ],
    "rawMessage": {},
    "quotedMessageId": 0,
    "quotedMessage": null
  }
  ```
</Accordion>

<Accordion title="User Object">
  The nested `User` object (used in `sender`, `receiver`, `mentionedUsers`) contains:

  | Parameter | Type | Description |
  | - | - | - |
  | `uid` | String | Unique identifier of the user |
  | `name` | String | Display name of the user |
  | `avatar` | String | URL to user's profile picture |
  | `link` | String | URL to user's profile page |
  | `role` | String | User role for access control |
  | `metadata` | JSONObject | Custom data set by developer |
  | `status` | String | User online status. Values: `"online"`, `"offline"` |
  | `statusMessage` | String | Custom status message |
  | `lastActiveAt` | long | Unix timestamp of last activity |
  | `hasBlockedMe` | boolean | Whether this user has blocked the logged-in user |
  | `blockedByMe` | boolean | Whether the logged-in user has blocked this user |
  | `tags` | Array\<String> | List of tags for user identification |
  | `deactivatedAt` | long | Unix timestamp when user was deactivated (0 if active) |
</Accordion>

<Accordion title="Group Object">
  The nested `Group` object (used in `receiver` for group messages) contains:

  | Parameter | Type | Description |
  | - | - | - |
  | `guid` | String | Unique identifier of the group |
  | `name` | String | Display name of the group |
  | `type` | String | Group type. Values: `"public"`, `"private"`, `"password"` |
  | `icon` | String | URL to group icon |
  | `description` | String | Group description |
  | `owner` | String | UID of group owner |
  | `metadata` | JSONObject | Custom data set by developer |
  | `membersCount` | int | Number of group members |
  | `tags` | Array\<String> | List of tags for group identification |
  | `hasJoined` | boolean | Whether logged-in user has joined |
  | `scope` | String | User's scope in group. Values: `"admin"`, `"moderator"`, `"participant"` |
</Accordion>

<Accordion title="ReactionCount Object">
  The nested `ReactionCount` object (used in `reactions` array) contains:

  | Parameter | Type | Description |
  | - | - | - |
  | `reaction` | String | The reaction emoji |
  | `count` | int | Total count of this reaction |
  | `reactedByMe` | boolean | Whether the logged-in user has reacted with this emoji |
</Accordion>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.