---
source_url: https://www.pubnub.com/docs/chat/unreal-chat-sdk/build/features/messages/drafts
title: Create message drafts
updated_at: 2026-06-04T11:09:53.352Z
---

> Documentation Index
> For a curated overview of PubNub documentation, see: https://www.pubnub.com/docs/llms.txt
> For the full list of all documentation pages, see: https://www.pubnub.com/docs/llms-full.txt


# Create message drafts

`MessageDraft` represents an unpublished message. Use it to:

* [Edit text](#update-message-text) before publishing
* Add [channel references](https://www.pubnub.com/docs/chat/unreal-chat-sdk/build/features/channels/references), [user mentions](https://www.pubnub.com/docs/chat/unreal-chat-sdk/build/features/users/mentions), and [links](https://www.pubnub.com/docs/chat/unreal-chat-sdk/build/features/messages/links)

Display message elements (mentions, references, links) in your UI by binding the [OnMessageDraftUpdatedWithSuggestions](#listen-for-message-draft-changes-with-suggestions) delegate.

:::note
CreateMessageDraft
is always synchronous
`CreateMessageDraft()` is a local, in-memory operation — it does not perform any network requests. It returns a `UPubnubChatMessageDraft*` directly and has no `Async` variant. The async/sync split applies to network methods (`Send()`, `SendAsync()`, etc.) called on the draft after it is created.
```cpp
UPubnubChatMessageDraft* Draft = Channel->CreateMessageDraft(MessageDraftConfig);
```
:::

###### Basics

Message drafts consist of `FPubnubChatMessageElement` structs, each containing a `Text` field (the display text) and optionally a `MentionTarget` field (for user mentions, channel references, or URLs). Each element also tracks its `Start` position and `Length` in the draft.

The `FPubnubChatMentionTarget` struct has a `MentionTargetType` enum property. Available types:

* `EPubnubChatMentionTargetType::PCMTT_User`
* `EPubnubChatMentionTargetType::PCMTT_Channel`
* `EPubnubChatMentionTargetType::PCMTT_Url`
* `EPubnubChatMentionTargetType::PCMTT_None` (plain text, no mention)

:::note Store draft messages locally
Unreal Chat SDK does not persist drafts. Implement your own local storage to save drafts across channel switches.
:::

:::note Safe mutations
The SDK validates all draft mutations (`InsertText`, `RemoveText`, `AppendText`, `AddMention`, `RemoveMention`). Operations that would corrupt an existing mention or link offset return an error in `FPubnubChatOperationResult` instead of silently breaking the draft's element structure.
:::

###### Class diagram

###### Example

Consider the message `Hey, I sent Alex this link on the #offtopic channel.` where:

* `Alex` is a reference to the user with the ID of `alex_d`
* `link` is a URL of the `www.pubnub.com` website
* `#offtopic` is a reference to the channel with the ID of `group.offtopic`

The list of `MessageElement` objects returned by the `MessageDraftChangeListener` is as follows:

| Part of Message | Element Type | Code Used to Create |
| --- | --- | --- |
| Hey, I sent | `Text` | [MessageDraft->Update("Hey, I sent Alex this link on the #offtopic channel.");](#update-message-text) |
| Alex | `MentionTarget` | [MessageDraft->AddMention(12, 4, UPubnubChatMessageDraftUtilities::CreateUserMentionTarget("alex_d"));](#add-message-element) |
| this | `Text` | [MessageDraft->Update("Hey, I sent Alex this link on the #offtopic channel.")](#update-message-text) |
| link | `MentionTarget` | [MessageDraft->AddMention(22, 4, UPubnubChatMessageDraftUtilities::CreateUrlMentionTarget("https://www.pubnub.com"));](#add-message-element) |
| on the | `Text` | [MessageDraft->Update("Hey, I sent Alex this link on the #offtopic channel.");](#update-message-text) |
| #offtopic | `MentionTarget` | [MessageDraft->AddMention(34, 9, UPubnubChatMessageDraftUtilities::CreateChannelMentionTarget("group.offtopic"));](#add-message-element) |
| channel. | `Text` | [MessageDraft->Update("Hey, I sent Alex this link on the #offtopic channel.");](#update-message-text) |

###### Internal mention format

The message draft format uses Markdown-like syntax internally, integrating links with the pattern `[link text](https://www.pubnub.com/docs/link target)`.

| Mention Type | Example |
| --- | --- |
| user | `[John Doe](https://www.pubnub.com/docs/pn-user://john_doe)` |
| channel | `[General Chat](https://www.pubnub.com/docs/pn-channel://group.chat.123)` |
| url | `[PubNub](https://www.pubnub.com)` |

Custom schemas like `pn-user://` and `pn-channel://` are used to identify user and channel mentions, while traditional URLs are supported as-is.

:::warning Adding message elements
This syntax is internal only. To add elements, use [AddMention()](#add-message-element).
:::

## Create a draft message

`CreateMessageDraft()` creates a ([MessageDraft object](https://www.pubnub.com/docs/chat/unreal-chat-sdk/learn/chat-entities/message-draft)) that can consist of:

* Plain text
* [Mentioned users](https://www.pubnub.com/docs/chat/unreal-chat-sdk/build/features/users/mentions)
* [Referenced channels](https://www.pubnub.com/docs/chat/unreal-chat-sdk/build/features/channels/references)
* [Links](https://www.pubnub.com/docs/chat/unreal-chat-sdk/build/features/messages/links)

### Method signature

#### C++ / Input parameters

```cpp
Channel->CreateMessageDraft(FPubnubChatMessageDraftConfig MessageDraftConfig = FPubnubChatMessageDraftConfig())
```

| Parameter | Description |
| --- | --- |
| `MessageDraftConfig`Type: [FPubnubChatMessageDraftConfig](#fpubnubchatmessagedraftconfig)Default: `FPubnubChatMessageDraftConfig()` | Configuration for the message draft, including settings such as initial content and metadata. |

#### FPubnubChatMessageDraftConfig

| Parameter | Description |
| --- | --- |
| `UserSuggestionSource`Type: `EPubnubChatMessageDraftSuggestionSource`Default: `PCMDSS_Global` | Source for user mention suggestions. `PCMDSS_Channel` limits suggestions to channel members; `PCMDSS_Global` searches all app users. |
| `IsTypingIndicatorTriggered`Type: `bool`Default: `false` | When `true`, the draft triggers typing indicator events on the channel when text is edited. |
| `UserLimit`Type: `int`Default: `10` | Maximum number of user mention suggestions to return (max: 100). |
| `ChannelLimit`Type: `int`Default: `10` | Maximum number of channel reference suggestions to return (max: 100). |

#### Output

| Parameter | Description |
| --- | --- |
| `UPubnubChatMessageDraft*`Type: `UPubnubChatMessageDraft*` | Pointer to the created `MessageDraft` object, which can be used to edit the draft, insert mentions, and eventually send the message. |

#### Blueprint

### Sample code

:::tip Reference code
This example is a self-contained code snippet ready to be run. Set up your Unreal project and follow the instructions in the lines marked with `ACTION REQUIRED` before running the code. Use it as a reference when working with other examples in this document.
:::

Create a message draft on a channel.

###### C++

###### Actor.h

```cpp
// blueprint.uy7kmex5
UFUNCTION(BlueprintCallable, Category = "PubnubChat|Samples|ChatChannel")
void CreateMessageDraftSample();
```

###### Actor.cpp

```cpp
// ACTION REQUIRED: Replace ASample_ChatChannel with name of your Actor class
void ASample_ChatChannel::CreateMessageDraftSample()
{
	// snippet.hide
	UPubnubChatChannel* Channel = nullptr;
	// snippet.show

	// Assumes Channel is a valid UPubnubChatChannel (e.g. from GetChannel)

	// Create a message draft to build and send a message (text, mentions, etc.)
	UPubnubChatMessageDraft* Draft = Channel->CreateMessageDraft();
}
```

###### Blueprint

## Listen for message draft changes

Bind to delegates on the `MessageDraft` object to receive notifications when the draft content changes.

##### Details

`OnMessageDraftUpdated` delegate:

* Fires when the draft content changes (after `InsertText`, `RemoveText`, `AddMention`, `RemoveMention`, `Update`, or `InsertSuggestedMention`)
* Provides the current list of message elements (`TArray<FPubnubChatMessageElement>`)
* Does not include suggestions (use `OnMessageDraftUpdatedWithSuggestions` for that)

### Delegate signature

| Delegate | Parameter |
| --- | --- |
| `FOnPubnubChatMessageDraftUpdated`Type: `TArray<FPubnubChatMessageElement>` | `MessageElements` |

### Sample code

:::tip Reference code
This example is a self-contained code snippet ready to be run. Set up your Unreal project and follow the instructions in the lines marked with `ACTION REQUIRED` before running the code. Use it as a reference when working with other examples in this document.
:::

Bind the delegate to your message draft.

###### Actor.h

```cpp
UFUNCTION(BlueprintCallable, Category = "PubnubChat|Samples|ChatMessageDraft")
void MessageDraftUpdatedSample();

void OnMessageDraftUpdate(const TArray<FPubnubChatMessageElement>& MessageElements);
```

###### Actor.cpp

```cpp
// ACTION REQUIRED: Replace ASample_ChatMessageDraft with name of your Actor class
void ASample_ChatMessageDraft::MessageDraftUpdatedSample()
{
	// snippet.hide
	UPubnubChatChannel* Channel = nullptr;
	// snippet.show

	// Assumes Channel is a valid UPubnubChatChannel (e.g. from GetChannel)

	UPubnubChatMessageDraft* MyMessageDraft = Channel->CreateMessageDraft();

	// Bind to receive draft content changes
	MyMessageDraft->OnMessageDraftUpdatedNative.AddUObject(this, &ASample_ChatMessageDraft::OnMessageDraftUpdate);

	// Trigger the delegate by updating the draft
	MyMessageDraft->Update("Review the message draft contents.");
}

// ACTION REQUIRED: Replace ASample_ChatMessageDraft with name of your Actor class
void ASample_ChatMessageDraft::OnMessageDraftUpdate(const TArray<FPubnubChatMessageElement>& MessageElements)
{
	for (const FPubnubChatMessageElement& Element : MessageElements)
	{
		UE_LOG(LogTemp, Log, TEXT("Draft Element Text: %s"), *Element.Text);
	}
}
```

## Listen for message draft changes (with suggestions)

Bind the `OnMessageDraftUpdatedWithSuggestions` delegate to receive draft changes along with suggestions for user mentions, links, and channel references.

##### Details

`OnMessageDraftUpdatedWithSuggestions` delegate:

* Fires when the draft content changes
* Provides the current state of message elements (`TArray<FPubnubChatMessageElement>`)
* Offers `FPubnubChatSuggestedMention` items suggesting user mentions, links, or channel references

Unlike `OnMessageDraftUpdated`, which only delivers content changes, this delegate also includes suggestion data for dynamic draft updates.

Example: typing `#Sup` returns channels like `Support` or `Support-Agents`. Default: 10 suggestions (max: 100).

### Delegate signature

| Delegate | Parameter |
| --- | --- |
| `FOnPubnubChatMessageDraftUpdatedWithSuggestions`Type: `TArray<FPubnubChatMessageElement>` | `MessageElements` |
| Type: `TArray<FPubnubChatSuggestedMention>` | `SuggestedMentions` |

### Sample code

:::tip Reference code
This example is a self-contained code snippet ready to be run. Set up your Unreal project and follow the instructions in the lines marked with `ACTION REQUIRED` before running the code. Use it as a reference when working with other examples in this document.
:::

Bind the delegate to your message draft.

###### Actor.h

```cpp
UFUNCTION(BlueprintCallable, Category = "PubnubChat|Samples|ChatMessageDraft")
void MessageDraftUpdatedWithSuggestionsSample();

void OnMessageDraftUpdateWithSuggestions(const TArray<FPubnubChatMessageElement>& MessageElements, const TArray<FPubnubChatSuggestedMention>& SuggestedMentions);
```

###### Actor.cpp

```cpp
// ACTION REQUIRED: Replace ASample_ChatMessageDraft with name of your Actor class
void ASample_ChatMessageDraft::MessageDraftUpdatedWithSuggestionsSample()
{
	// snippet.hide
	UPubnubChatChannel* Channel = nullptr;
	// snippet.show

	// Assumes Channel is a valid UPubnubChatChannel (e.g. from GetChannel)

	UPubnubChatMessageDraft* MyMessageDraft = Channel->CreateMessageDraft();

	// Bind to receive draft content changes with suggestions for @user and #channel patterns
	MyMessageDraft->OnMessageDraftUpdatedWithSuggestionsNative.AddUObject(this, &ASample_ChatMessageDraft::OnMessageDraftUpdateWithSuggestions);

	// Trigger the delegate by updating the draft with mentions
	MyMessageDraft->Update("Discuss this with @Alex and review in #general.");
}

// ACTION REQUIRED: Replace ASample_ChatMessageDraft with name of your Actor class
void ASample_ChatMessageDraft::OnMessageDraftUpdateWithSuggestions(const TArray<FPubnubChatMessageElement>& MessageElements, const TArray<FPubnubChatSuggestedMention>& SuggestedMentions)
{
	for (const FPubnubChatMessageElement& Element : MessageElements)
	{
		UE_LOG(LogTemp, Log, TEXT("Draft Element Text: %s"), *Element.Text);
	}

	for (const FPubnubChatSuggestedMention& Suggestion : SuggestedMentions)
	{
		UE_LOG(LogTemp, Log, TEXT("Suggested Mention: Replace '%s' with '%s'"), *Suggestion.ReplaceFrom, *Suggestion.ReplaceTo);
	}
}
```

## Add message element

`AddMention()` adds a user mention, channel reference or a link specified by a mention target at a given position.

### Method signature

```cpp
MessageDraft->AddMention(int Position, int Length, const FPubnubChatMentionTarget MentionTarget)
```

| Parameter | Description |
| --- | --- |
| `Position` *Type: `int`Default: n/a | Position of a character in a message where the message element you want to insert starts. It's counted from the beginning of the message (including spaces), with `0` as the first character. |
| `Length` *Type: `int`Default: n/a | Number of characters the message element should occupy in the draft message's text. |
| `MentionTarget` *Type: `FPubnubChatMentionTarget`Default: n/a | Mention target struct. Create using `UPubnubChatMessageDraftUtilities` factory methods. Available mention types (`EPubnubChatMentionTargetType`): PCMTT_User, PCMTT_Channel, PCMTT_Url |

#### Output

| Type | Description |
| --- | --- |
| `FPubnubChatOperationResult` | Operation result with `Error` (bool) and `ErrorMessage` (FString). |

### Sample code

:::tip Reference code
This example is a self-contained code snippet ready to be run. Set up your Unreal project and follow the instructions in the lines marked with `ACTION REQUIRED` before running the code. Use it as a reference when working with other examples in this document.
:::

Create the `Hello Alex! I have sent you this link on the #offtopic channel.` message where `Alex` is a user mention, `link` is a URL, and `#offtopic` is a channel reference.

###### Actor.h

```cpp
UFUNCTION(BlueprintCallable, Category = "PubnubChat|Samples|ChatMessageDraft")
void MessageDraftAddMentionSample();
```

###### Actor.cpp

```cpp
// ACTION REQUIRED: Replace ASample_ChatMessageDraft with name of your Actor class
void ASample_ChatMessageDraft::MessageDraftAddMentionSample()
{
	// snippet.hide
	UPubnubChatChannel* Channel = nullptr;
	// snippet.show

	// Assumes Channel is a valid UPubnubChatChannel (e.g. from GetChannel)

	UPubnubChatMessageDraft* MyMessageDraft = Channel->CreateMessageDraft();

	MyMessageDraft->InsertText(0, "Hello Alex! I have sent you this link on the #offtopic channel.");

	// Add a user mention for "Alex"
	FString UserName = "Alex";
	FPubnubChatMentionTarget UserMentionTarget = UPubnubChatMessageDraftUtilities::CreateUserMentionTarget(UserName);
	MyMessageDraft->AddMention(6, UserName.Len(), UserMentionTarget);

	// Add a URL link for "this"
	FString Url = "https://www.example.com";
	FPubnubChatMentionTarget UrlMentionTarget = UPubnubChatMessageDraftUtilities::CreateUrlMentionTarget(Url);
	int LinkStartPosition = 33;
	MyMessageDraft->AddMention(LinkStartPosition, 4, UrlMentionTarget);

	// Add a channel reference for "#offtopic"
	FString ChannelName = "offtopic";
	FPubnubChatMentionTarget ChannelMentionTarget = UPubnubChatMessageDraftUtilities::CreateChannelMentionTarget(ChannelName);
	int ChannelStartPosition = LinkStartPosition + 4 + 8;
	MyMessageDraft->AddMention(ChannelStartPosition, ChannelName.Len() + 1, ChannelMentionTarget);

	MyMessageDraft->Send();
}
```

## Remove message element

`RemoveMention()` removes a user mention, channel reference, or a link at a given position.

### Method signature

```cpp
MessageDraft->RemoveMention(int Position)
```

| Parameter | Description |
| --- | --- |
| `Position` *Type: `int`Default: n/a | Position of the first character of the message element you want to remove. |

:::warning Position value
If you don't provide the position of the first character of the message element to remove, it isn't removed.
:::

#### Output

| Type | Description |
| --- | --- |
| `FPubnubChatOperationResult` | Operation result with `Error` (bool) and `ErrorMessage` (FString). |

### Sample code

:::tip Reference code
This example is a self-contained code snippet ready to be run. Set up your Unreal project and follow the instructions in the lines marked with `ACTION REQUIRED` before running the code. Use it as a reference when working with other examples in this document.
:::

Remove the URL element from the word `link` in the `Hello Alex! I have sent you this link on the #offtopic channel.` message.

###### Actor.h

```cpp
UFUNCTION(BlueprintCallable, Category = "PubnubChat|Samples|ChatMessageDraft")
void MessageDraftRemoveMentionSample();
```

###### Actor.cpp

```cpp
// ACTION REQUIRED: Replace ASample_ChatMessageDraft with name of your Actor class
void ASample_ChatMessageDraft::MessageDraftRemoveMentionSample()
{
	// snippet.hide
	UPubnubChatMessageDraft* MessageDraft = nullptr;
	// snippet.show

	// Assumes MessageDraft is a valid UPubnubChatMessageDraft with existing mentions
	// e.g. the message reads: "Hello Alex! I have sent you this link on the #offtopic channel."

	// Remove the link mention at position 33
	MessageDraft->RemoveMention(33);
}
```

## Update message text

`Update()` replaces the text of a [draft message](https://www.pubnub.com/docs/chat/unreal-chat-sdk/build/features/messages/drafts) with new content.

:::warning Removing message elements
The SDK preserves message elements when possible. If element text is modified, that element is removed.
:::

### Method signature

```cpp
MessageDraft->Update(const FString& NewText)
```

| Parameter | Description |
| --- | --- |
| `NewText` *Type: `FString`Default: n/a | The new full draft text. |

#### Output

| Type | Description |
| --- | --- |
| `FPubnubChatOperationResult` | Operation result with `Error` (bool) and `ErrorMessage` (FString). |

### Sample code

:::tip Reference code
This example is a self-contained code snippet ready to be run. Set up your Unreal project and follow the instructions in the lines marked with `ACTION REQUIRED` before running the code. Use it as a reference when working with other examples in this document.
:::

Change the message `I sent Alex this picture.` to `I did not send Alex this picture.` where `Alex` is a user mention.

###### Actor.h

```cpp
UFUNCTION(BlueprintCallable, Category = "PubnubChat|Samples|ChatMessageDraft")
void MessageDraftUpdateSample();
```

###### Actor.cpp

```cpp
// ACTION REQUIRED: Replace ASample_ChatMessageDraft with name of your Actor class
void ASample_ChatMessageDraft::MessageDraftUpdateSample()
{
	// snippet.hide
	UPubnubChatMessageDraft* MessageDraft = nullptr;
	// snippet.show

	// Assumes MessageDraft is a valid UPubnubChatMessageDraft
	// e.g. the message reads: "I sent [Alex] this picture." where [Alex] is a user mention

	MessageDraft->Update("I did not send Alex this picture.");
	// The message now reads: "I did not send [Alex] this picture."
	// The mention is preserved because its text wasn't changed
}
```

:::note Mention text changes
If you decided to change the name `Alex` to some other name, the mention would be removed because your updated text's index coincided with an existing mention.
For more manual control over inserting and removing parts of a message, refer to [Insert message text](#insert-message-text) and [Remove message text](#remove-message-text).
:::

## Insert suggested message element

Inserts a message element returned by the [OnMessageDraftUpdatedWithSuggestions](#listen-for-message-draft-changes-with-suggestions) delegate into the `MessageDraft`.

:::warning Text must match
The `SuggestedMention` must be up to date with the message text, that is, `SuggestedMention.ReplaceFrom` must match the message draft at position `SuggestedMention.ReplaceFrom`, otherwise an exception is thrown.
:::

### Method signature

```cpp
MessageDraft->InsertSuggestedMention(const FPubnubChatSuggestedMention SuggestedMention)
```

| Parameter | Description |
| --- | --- |
| `SuggestedMention` *Type: `FPubnubChatSuggestedMention`Default: n/a | A user, channel, or URL suggestion obtained from the [OnMessageDraftUpdatedWithSuggestions](#listen-for-message-draft-changes-with-suggestions) delegate. The `ReplaceFrom` text must match the current draft text at `Offset`. |

#### Output

| Type | Description |
| --- | --- |
| `FPubnubChatOperationResult` | Operation result with `Error` (bool) and `ErrorMessage` (FString). |

### Sample code

:::tip Reference code
This example is a self-contained code snippet ready to be run. Set up your Unreal project and follow the instructions in the lines marked with `ACTION REQUIRED` before running the code. Use it as a reference when working with other examples in this document.
:::

Bind the delegate and insert a suggested element.

###### Actor.h

```cpp
UFUNCTION(BlueprintCallable, Category = "PubnubChat|Samples|ChatMessageDraft")
void MessageDraftInsertSuggestedMentionSample();

void OnMessageDraftUpdateWithSuggestions_InsertSample(const TArray<FPubnubChatMessageElement>& MessageElements, const TArray<FPubnubChatSuggestedMention>& SuggestedMentions);
```

###### Actor.cpp

```cpp
// ACTION REQUIRED: Replace ASample_ChatMessageDraft with name of your Actor class
void ASample_ChatMessageDraft::MessageDraftInsertSuggestedMentionSample()
{
	// snippet.hide
	UPubnubChatChannel* Channel = nullptr;
	// snippet.show

	// Assumes Channel is a valid UPubnubChatChannel (e.g. from GetChannel)

	UPubnubChatMessageDraft* MyMessageDraft = Channel->CreateMessageDraft();

	// Bind to receive suggestions and automatically insert the first one
	MyMessageDraft->OnMessageDraftUpdatedWithSuggestionsNative.AddUObject(this, &ASample_ChatMessageDraft::OnMessageDraftUpdateWithSuggestions_InsertSample);

	// Trigger the delegate and suggestions
	MyMessageDraft->Update("Please coordinate with @Al for the meeting.");
}

// ACTION REQUIRED: Replace ASample_ChatMessageDraft with name of your Actor class
void ASample_ChatMessageDraft::OnMessageDraftUpdateWithSuggestions_InsertSample(const TArray<FPubnubChatMessageElement>& MessageElements, const TArray<FPubnubChatSuggestedMention>& SuggestedMentions)
{
	// snippet.hide
	UPubnubChatMessageDraft* MyMessageDraft = nullptr;
	// snippet.show

	if (SuggestedMentions.Num() > 0)
	{
		const FPubnubChatSuggestedMention& FirstSuggestion = SuggestedMentions[0];
		MyMessageDraft->InsertSuggestedMention(FirstSuggestion);
		UE_LOG(LogTemp, Log, TEXT("Inserted suggested mention: %s"), *FirstSuggestion.ReplaceTo);
	}
}
```

## Insert message text

`InsertText()` lets you insert plain text in the [draft message](https://www.pubnub.com/docs/chat/unreal-chat-sdk/build/features/messages/drafts) at a given position from the beginning of the message.

:::warning Removing message elements
Inserting text **strictly inside** a mention span (not at its start or end position) removes the mention and converts its text to plain text. Inserting at the exact start or end boundary of a mention preserves the mention.
:::

### Method signature

```cpp
MessageDraft->InsertText(int Position, FString Text)
```

| Parameter | Description |
| --- | --- |
| `Position` *Type: `int`Default: n/a | Position of a character in a message where the text you want to insert starts. It's counted from the beginning of the message (including spaces), with `0` as the first character. |
| `Text` *Type: `FString`Default: n/a | Text that you want to insert. |

#### Output

| Type | Description |
| --- | --- |
| `FPubnubChatOperationResult` | Operation result with `Error` (bool) and `ErrorMessage` (FString). |

### Sample code

:::tip Reference code
This example is a self-contained code snippet ready to be run. Set up your Unreal project and follow the instructions in the lines marked with `ACTION REQUIRED` before running the code. Use it as a reference when working with other examples in this document.
:::

In the message `Check this support article https://www.support-article.com/.`, add the word `out` between the words `Check` and `this`.

###### Actor.h

```cpp
UFUNCTION(BlueprintCallable, Category = "PubnubChat|Samples|ChatMessageDraft")
void MessageDraftInsertTextSample();
```

###### Actor.cpp

```cpp
// ACTION REQUIRED: Replace ASample_ChatMessageDraft with name of your Actor class
void ASample_ChatMessageDraft::MessageDraftInsertTextSample()
{
	// snippet.hide
	UPubnubChatMessageDraft* MyMessageDraft = nullptr;
	// snippet.show

	// Assumes MyMessageDraft is a valid UPubnubChatMessageDraft

	// Set initial text in the message draft
	MyMessageDraft->Update(TEXT("Check this support article https://www.support-article.com/."));

	// Insert "out " at position 6 ("Check " is 6 characters long)
	int InsertPosition = 6;
	MyMessageDraft->InsertText(InsertPosition, TEXT("out "));

	// The draft now reads: "Check out this support article https://www.support-article.com/."
}
```

## Append text

`AppendText()` adds text at the end of the [draft message](https://www.pubnub.com/docs/chat/unreal-chat-sdk/build/features/messages/drafts). Equivalent to calling `InsertText()` at position `GetCurrentText().Len()`.

### Method signature

```cpp
MessageDraft->AppendText(const FString Text)
```

| Parameter | Description |
| --- | --- |
| `Text` *Type: `FString`Default: n/a | Text to append to the end of the draft. Must be non-empty. |

#### Output

| Type | Description |
| --- | --- |
| `FPubnubChatOperationResult` | Operation result with `Error` (bool) and `ErrorMessage` (FString). |

## Remove message text

`RemoveText()` lets you remove plain text from the [draft message](https://www.pubnub.com/docs/chat/unreal-chat-sdk/build/features/messages/drafts) at a given position from the beginning of the message.

:::warning Removing message elements
If the range overlaps an existing mention or link element, the operation returns an error (`FPubnubChatOperationResult.Error = true`). Use [RemoveMention()](#remove-message-element) to explicitly remove a mention element.
:::

### Method signature

```cpp
MessageDraft->RemoveText(int Position, int Length)
```

| Parameter | Description |
| --- | --- |
| `Position` *Type: `int`Default: n/a | Position of a character in a message where the text you want to insert starts. It's counted from the beginning of the message (including spaces), with `0` as the first character. |
| `Length` *Type: `int`Default: n/a | How many characters to remove, starting at the given `Position`. |

#### Output

| Type | Description |
| --- | --- |
| `FPubnubChatOperationResult` | Operation result with `Error` (bool) and `ErrorMessage` (FString). |

### Sample code

:::tip Reference code
This example is a self-contained code snippet ready to be run. Set up your Unreal project and follow the instructions in the lines marked with `ACTION REQUIRED` before running the code. Use it as a reference when working with other examples in this document.
:::

In the message `Check out this support article https://www.support-article.com/.`, remove the word `out`.

###### Actor.h

```cpp
UFUNCTION(BlueprintCallable, Category = "PubnubChat|Samples|ChatMessageDraft")
void MessageDraftRemoveTextSample();
```

###### Actor.cpp

```cpp
// ACTION REQUIRED: Replace ASample_ChatMessageDraft with name of your Actor class
void ASample_ChatMessageDraft::MessageDraftRemoveTextSample()
{
	// snippet.hide
	UPubnubChatMessageDraft* MyMessageDraft = nullptr;
	// snippet.show

	// Assumes MyMessageDraft is a valid UPubnubChatMessageDraft

	// Set initial text in the message draft
	MyMessageDraft->Update(TEXT("Check out this support article https://www.support-article.com/."));

	// Remove "out " starting at position 6 (4 characters including the trailing space)
	int RemovePosition = 6;
	int RemoveLength = 4;
	MyMessageDraft->RemoveText(RemovePosition, RemoveLength);

	// The draft now reads: "Check this support article https://www.support-article.com/."
}
```

## Send a draft message

`Send()` publishes the draft message with all [mentioned users](https://www.pubnub.com/docs/chat/unreal-chat-sdk/build/features/users/mentions), [links](https://www.pubnub.com/docs/chat/unreal-chat-sdk/build/features/messages/links), and [referenced channels](https://www.pubnub.com/docs/chat/unreal-chat-sdk/build/features/channels/references). Mentioning users also emits [mention events](https://www.pubnub.com/docs/chat/unreal-chat-sdk/build/features/custom-events#events-for-mentions).

### Method signature

```cpp
MessageDraft->Send(FPubnubChatSendTextParams SendTextParams = FPubnubChatSendTextParams())
```

| Parameter | Description |
| --- | --- |
| `SendTextParams`Type: `FPubnubChatSendTextParams`Default: `FPubnubChatSendTextParams()` | Struct providing additional parameters. |
| `> StoreInHistory`Type: `bool`Default: `true` | If `true`, the messages are stored in Message Persistence. If not specified, the Message Persistence configuration from the Admin Portal keyset is used. |
| `> SendByPost`Type: `bool`Default: `false` | When `true`, the SDK uses HTTP POST to publish the messages. |
| `> Meta`Type: `FString`Default: `""` | Publish additional metadata with the request. |

User mentions, channel references, and links are not passed in `SendTextParams`. They are added to the [MessageDraft](https://www.pubnub.com/docs/chat/unreal-chat-sdk/learn/chat-entities/message-draft) object through [AddMention()](#add-message-element) and serialized automatically when `Send()` is called. To [quote](https://www.pubnub.com/docs/chat/unreal-chat-sdk/build/features/messages/quotes) another message, use [SetQuotedMessage()](#set-quoted-message) before calling `Send()`.

#### Output

| Type | Description |
| --- | --- |
| `FPubnubChatOperationResult` | Operation result with `Error` (bool) and `ErrorMessage` (FString). |

### Sample code

:::tip Reference code
This example is a self-contained code snippet ready to be run. Set up your Unreal project and follow the instructions in the lines marked with `ACTION REQUIRED` before running the code. Use it as a reference when working with other examples in this document.
:::

Send a draft message containing just plain text.

###### Actor.h

```cpp
UFUNCTION(BlueprintCallable, Category = "PubnubChat|Samples|ChatMessageDraft")
void MessageDraftSendSample();
```

###### Actor.cpp

```cpp
// ACTION REQUIRED: Replace ASample_ChatMessageDraft with name of your Actor class
void ASample_ChatMessageDraft::MessageDraftSendSample()
{
	// snippet.hide
	UPubnubChatChannel* Channel = nullptr;
	// snippet.show

	// Assumes Channel is a valid UPubnubChatChannel (e.g. from GetChannel)

	UPubnubChatMessageDraft* MyMessageDraft = Channel->CreateMessageDraft();
	MyMessageDraft->Update("Hello Alex!");

	FPubnubChatOperationResult Result = MyMessageDraft->Send();
}
```

## Send a draft message (async)

`SendAsync()` is the asynchronous variant of `Send()`. It sends the draft on a background thread and calls the provided delegate when the operation completes.

### Method signature

```cpp
MessageDraft->SendAsync(FOnPubnubChatOperationResponse OnOperationResponse, FPubnubChatSendTextParams SendTextParams = FPubnubChatSendTextParams())
```

| Parameter | Description |
| --- | --- |
| `OnOperationResponse`Type: `FOnPubnubChatOperationResponse` | Callback executed when the operation completes. |
| `SendTextParams`Type: `FPubnubChatSendTextParams` | Same parameters as `Send()`. |

## Get current draft text

`GetCurrentText()` returns the current full draft text by concatenating all message elements.

### Method signature

```cpp
MessageDraft->GetCurrentText()
```

#### Output

| Type | Description |
| --- | --- |
| `FString` | The full draft text string. |

## Get message elements

`GetMessageElements()` returns a copy of the current message elements (text segments and mentions with position and target).

### Method signature

```cpp
MessageDraft->GetMessageElements()
```

#### Output

| Type | Description |
| --- | --- |
| `TArray<FPubnubChatMessageElement>` | Array of message elements in the draft. |

##### FPubnubChatMessageElement

| Field | Type | Description |
| --- | --- | --- |
| `Text` | `FString` | The display text of this element. |
| `MentionTarget` | `FPubnubChatMentionTarget` | The mention target (user, channel, or URL). `MentionTargetType` is `PCMTT_None` for plain text. |
| `Start` | `int` | Start position (0-based) in the draft. |
| `Length` | `int` | Length of this element in the draft. |

## Get text to send

`GetTextToSend()` returns the serialized draft text as it would be sent by `Send()`. Mentions are encoded as markdown links (for example, `[Alex](https://www.pubnub.com/docs/pn-user://alex_d)`). Use this to preview or parse the final message format.

### Method signature

```cpp
MessageDraft->GetTextToSend()
```

#### Output

| Type | Description |
| --- | --- |
| `FString` | Serialized draft text with mentions as markdown links. Empty if the draft is empty. |

## Set quoted message

`SetQuotedMessage()` attaches (or clears) a [quoted message](https://www.pubnub.com/docs/chat/unreal-chat-sdk/build/features/messages/quotes) on the draft. The quoted message is sent alongside the draft text when [Send()](#send-a-draft-message) is called. Pass `nullptr` to remove any existing quoted message.

### Method signature

```cpp
MessageDraft->SetQuotedMessage(UPubnubChatMessage* InQuotedMessage)
```

| Parameter | Description |
| --- | --- |
| `InQuotedMessage` *Type: `UPubnubChatMessage*`Default: n/a | The message to quote, or `nullptr` to clear the quoted message. |

### Sample code

:::tip Reference code
This example is a self-contained code snippet ready to be run. Set up your Unreal project and follow the instructions in the lines marked with `ACTION REQUIRED` before running the code. Use it as a reference when working with other examples in this document.
:::

Quote a message using a message draft.

###### Actor.h

```cpp
UFUNCTION(BlueprintCallable, Category = "PubnubChat|Samples|ChatMessageDraft")
void QuoteMessageSample();
```

###### Actor.cpp

```cpp
// ACTION REQUIRED: Replace ASample_ChatMessageDraft with name of your Actor class
void ASample_ChatMessageDraft::QuoteMessageSample()
{
	// snippet.hide
	UPubnubChatChannel* Channel = nullptr;
	UPubnubChatMessage* Message = nullptr;
	// snippet.show

	// Assumes Channel is a valid UPubnubChatChannel (e.g. from GetChannel)
	// Assumes Message is a valid UPubnubChatMessage to quote (e.g. from channel history)

	// Send a message that quotes another message
	UPubnubChatMessageDraft* MessageDraft = Channel->CreateMessageDraft();
	MessageDraft->SetQuotedMessage(Message);
	MessageDraft->InsertText(0, "Quoting this: ");
	MessageDraft->Send();
}
```

## Get quoted message

`GetQuotedMessage()` returns the quoted message attached to the draft, if any.

### Method signature

```cpp
MessageDraft->GetQuotedMessage()
```

#### Output

| Type | Description |
| --- | --- |
| `UPubnubChatMessage*` | The quoted message, or `nullptr` if none is set. |