diff --git a/callwidget.cpp b/callwidget.cpp
index ddb01dbc9682513f92b5d9d735afefac2666c858..26769185fa5e582c66c26b90ef3bbf2d92ea698c 100644
--- a/callwidget.cpp
+++ b/callwidget.cpp
@@ -976,18 +976,30 @@ CallWidget::setupChatView(const lrc::api::conversation::Info& convInfo)
     ui->sendContactRequestButton->setVisible(shouldShowSendContactRequestBtn);
 
     ui->messageView->setMessagesVisibility(false);
-    Utils::oneShotConnect(ui->messageView, &MessageWebView::messagesCleared,
-        [this, convInfo] {
-            auto convModel = LRCInstance::getCurrentConversationModel();
-            ui->messageView->printHistory(*convModel, convInfo.interactions);
-            Utils::oneShotConnect(ui->messageView, &MessageWebView::messagesLoaded,
-                [this] {
-                    ui->messageView->setMessagesVisibility(true);
+    Utils::oneShotConnect(ui->messageView, &MessageWebView::sendMessageContentSaved,
+        [this, &convInfo, &accountInfo, lastConvUid = lastConvUid_](const QString& content) {
+            if (!lastConvUid.empty()) {
+                LRCInstance::setContentDraft(
+                    lastConvUid.c_str(), accountInfo.id.c_str(), content);
+            }
+            Utils::oneShotConnect(ui->messageView, &MessageWebView::messagesCleared,
+                [this, &convInfo] {
+                    auto convModel = LRCInstance::getCurrentConversationModel();
+                    ui->messageView->printHistory(*convModel, convInfo.interactions);
+                    Utils::oneShotConnect(ui->messageView, &MessageWebView::messagesLoaded,
+                        [this] {
+                            ui->messageView->setMessagesVisibility(true);
+                        });
+                    setConversationProfileData(convInfo);
                 });
-            setConversationProfileData(convInfo);
+            ui->messageView->setInvitation(false);
+            ui->messageView->clear();
+            auto restoredContent = LRCInstance::getContentDraft(
+                convInfo.uid.c_str(), accountInfo.id.c_str());
+            ui->messageView->setSendMessageContent(restoredContent);
+            ui->smartList->update();
         });
-    ui->messageView->setInvitation(false);
-    ui->messageView->clear();
+    ui->messageView->requestSendMessageContent();
 }
 
 void
diff --git a/conversationitemdelegate.cpp b/conversationitemdelegate.cpp
index 3733a76dccece81211d5cec48b252b1beae9f5c1..eba90003ee88ff5985fd99a4da5fd5c6182d88a8 100644
--- a/conversationitemdelegate.cpp
+++ b/conversationitemdelegate.cpp
@@ -272,6 +272,32 @@ ConversationItemDelegate::paintConversationItem(QPainter* painter,
     }
 
     // bottom-right: last interaction snippet or call state (if in call)
+    auto draft = index.data(static_cast<int>(SmartListModel::Role::Draft)).value<QString>();
+    if (!draft.isEmpty()) {
+        painter->save();
+        uint cp = 0x270F;
+        auto emojiString = QString::fromUcs4(&cp, 1);
+        QFont emojiMsgFont(QStringLiteral("Segoe UI Emoji"));
+        emojiMsgFont.setPointSize(scalingRatio > 1.0 ? fontSize_ - 2 : fontSize_);
+
+        QString text{ tr("Draft") };
+        int widthText{ QFontMetrics(font).width(text) };
+        int widthEmoji{ QFontMetrics(emojiMsgFont).width(emojiString) };
+        int margin { 4 };
+
+        painter->setFont(font);
+        painter->setPen(QColor(207, 83, 0));
+        painter->drawText(rectInfo2, Qt::AlignVCenter | Qt::AlignRight, text);
+
+        rectInfo2.moveTop(rectInfo2.top() - 2);
+        painter->setOpacity(0.7);
+        painter->setFont(emojiMsgFont);
+        painter->drawText(rectInfo2.right() - widthText - widthEmoji - margin, rectInfo2.y(),
+                          widthEmoji, rectInfo2.height(), Qt::AlignVCenter, emojiString);
+        painter->restore();
+        return;
+    }
+
     if (index.data(static_cast<int>(SmartListModel::Role::InCall)).value<bool>()) {
         QString callStateStr = index.data(static_cast<int>(SmartListModel::Role::CallStateStr)).value<QString>();
         if (!callStateStr.isNull()) {
diff --git a/lrcinstance.h b/lrcinstance.h
index 82d14c6037624df5d928f4961b64b02ef2244564..056f0f49aa585775e8384b290833f6826cb3406d 100644
--- a/lrcinstance.h
+++ b/lrcinstance.h
@@ -338,6 +338,22 @@ public:
             f();
         }
     }
+
+    static QString getContentDraft(const QString& convUid,
+                                   const QString& accountId)
+    {
+        auto draftKey = accountId + "_" + convUid;
+        return instance().contentDrafts_[draftKey];
+    }
+
+    static void setContentDraft(const QString& convUid,
+                                const QString& accountId,
+                                const QString& content)
+    {
+        auto draftKey = accountId + "_" + convUid;
+        instance().contentDrafts_[draftKey] = content;
+    }
+
 signals:
     void accountListChanged();
 
@@ -355,4 +371,5 @@ private:
     AccountListModel accountListModel_;
     std::string selectedAccountId_;
     std::string selectedConvUid_;
+    MapStringString contentDrafts_;
 };
diff --git a/messagewebview.cpp b/messagewebview.cpp
index 0553c8429b4d091a12bf54fa680f7bb201ff308e..e22923b639cfb4d68ab230d0364a6547a16af421 100644
--- a/messagewebview.cpp
+++ b/messagewebview.cpp
@@ -457,6 +457,21 @@ MessageWebView::displayNavbar(bool display)
     page()->runJavaScript(s, QWebEngineScript::MainWorld);
 }
 
+void
+MessageWebView::requestSendMessageContent()
+{
+    QString s = QString::fromLatin1("requestSendMessageContent();");
+    page()->runJavaScript(s, QWebEngineScript::MainWorld);
+}
+
+void
+MessageWebView::setSendMessageContent(const QString& content)
+{
+    QString s = QString::fromLatin1("setSendMessageContent(`%1`);")
+        .arg(content);
+    page()->runJavaScript(s, QWebEngineScript::MainWorld);
+}
+
 // JS bridging incoming
 Q_INVOKABLE int
 PrivateBridging::log(const QString& arg)
@@ -715,7 +730,7 @@ PrivateBridging::emitPasteKeyDetected()
     return 0;
 }
 
-int
+Q_INVOKABLE int
 PrivateBridging::openAudioRecorder(int spikePosX, int spikePosY)
 {
     //call the open audio recorder function in messageweview
@@ -729,7 +744,7 @@ PrivateBridging::openAudioRecorder(int spikePosX, int spikePosY)
     return 0;
 }
 
-int
+Q_INVOKABLE int
 PrivateBridging::openVideoRecorder(int spikePosX, int spikePosY)
 {
     //call the open video recorder function in messageweview
@@ -741,4 +756,18 @@ PrivateBridging::openVideoRecorder(int spikePosX, int spikePosY)
         qDebug() << "JS bridging - exception during openVideoRecorder!";
     }
     return 0;
+}
+
+Q_INVOKABLE int
+PrivateBridging::saveSendMessageContent(const QString& arg)
+{
+    try {
+        if (auto messageView = qobject_cast<MessageWebView*>(this->parent())) {
+            emit messageView->sendMessageContentSaved(arg);
+        }
+    } catch (...) {
+        qDebug() << "JS bridging - exception during saveSendMessageContent!";
+    }
+    return 0;
+
 }
\ No newline at end of file
diff --git a/messagewebview.h b/messagewebview.h
index d782aff8fe9844549750910af61b9ac21d681c26..3573ec49f086698b786f028eceb38e355ddbc959 100644
--- a/messagewebview.h
+++ b/messagewebview.h
@@ -53,6 +53,7 @@ public:
     Q_INVOKABLE int emitPasteKeyDetected();
     Q_INVOKABLE int openAudioRecorder(int spikePosX,int spikePosY);
     Q_INVOKABLE int openVideoRecorder(int spikePosX,int spikePosY);
+    Q_INVOKABLE int saveSendMessageContent(const QString& arg);
 };
 
 class MessageWebView : public QWebEngineView
@@ -97,6 +98,8 @@ public:
     void updateChatviewFrame(bool accountEnabled, bool isBanned, bool isTemporary,
                              const QString& alias, const QString& bestId);
     void displayNavbar(bool display);
+    void requestSendMessageContent();
+    void setSendMessageContent(const QString& content);
 
 protected:
 
@@ -114,6 +117,7 @@ signals:
     void textSelectedReady();
     void pasteKeyDetected();
     void invitationAccepted();
+    void sendMessageContentSaved(const QString& content);
 
 private slots:
     void slotLoadFinished();
diff --git a/smartlistmodel.cpp b/smartlistmodel.cpp
index 234917d43597abb6579a792693580e57b49eec88..0c326d03313e73ae08c00418d95198bab87ae674 100644
--- a/smartlistmodel.cpp
+++ b/smartlistmodel.cpp
@@ -239,6 +239,8 @@ SmartListModel::getConversationItemData(const conversation::Info& item,
     }
     case Role::SectionName:
         return QVariant(QString());
+    case Role::Draft:
+        return LRCInstance::getContentDraft(item.uid.c_str(), accountInfo.id.c_str());
     }
     return QVariant();
 }
diff --git a/smartlistmodel.h b/smartlistmodel.h
index 76657ac66e8ba77952fb3170422400acbffcbb3c..108e08b1c57b442bf1f64caa1ccf68af221fefa7 100644
--- a/smartlistmodel.h
+++ b/smartlistmodel.h
@@ -58,7 +58,8 @@ public:
         InCall,
         CallStateStr,
         SectionName,
-        AccountId
+        AccountId,
+        Draft
     };
 
     explicit SmartListModel(const std::string& accId,