diff --git a/src/api/conversationmodel.h b/src/api/conversationmodel.h
index 7a96dcf158217a2ffb3def02dfc932fcb5dc2977..29face79f9d77ab3221f85185e5f09936a8557fd 100644
--- a/src/api/conversationmodel.h
+++ b/src/api/conversationmodel.h
@@ -167,6 +167,12 @@ public:
      * @param interactionId
      */
     void clearInteractionFromConversation(const std::string& convId, const uint64_t& interactionId);
+    /**
+     * Retry to send a message. In fact, will delete the previous interaction and resend a new one.
+     * @param convId
+     * @param interactionId
+     */
+    void retryInteraction(const std::string& convId, const uint64_t& interactionId);
     /**
      * delete obsolete history from the database
      * @param days, number of days from today. Below this date, interactions will be deleted
diff --git a/src/conversationmodel.cpp b/src/conversationmodel.cpp
index 5e2b3748ee83693fa8efb98b83c003c3ad82d246..805fd8a638d18448adf80b97204c2dc494adf716 100644
--- a/src/conversationmodel.cpp
+++ b/src/conversationmodel.cpp
@@ -21,6 +21,7 @@
 
 //Qt
 #include <QtCore/QTimer>
+#include <QFileInfo>
 
 // daemon
 #include <account_const.h>
@@ -756,6 +757,54 @@ ConversationModel::clearInteractionFromConversation(const std::string& convId, c
     }
 }
 
+void
+ConversationModel::retryInteraction(const std::string& convId, const uint64_t& interactionId)
+{
+    auto conversationIdx = pimpl_->indexOf(convId);
+    if (conversationIdx == -1)
+        return;
+
+    auto interactionType = interaction::Type::INVALID;
+    auto body = std::string();
+    {
+        std::lock_guard<std::mutex> lk(pimpl_->interactionsLocks[convId]);
+        try {
+            auto& conversation = pimpl_->conversations.at(conversationIdx);
+
+            auto& interactions = conversation.interactions;
+            auto it = interactions.find(interactionId);
+            if (it == interactions.end())
+                return;
+
+            if (!interaction::isOutgoing(it->second))
+                return;  // Do not retry non outgoing info
+
+            if (it->second.type == interaction::Type::TEXT
+            || it->second.type == interaction::Type::OUTGOING_DATA_TRANSFER) {
+                body = it->second.body;
+                interactionType = it->second.type;
+            } else
+                return;
+
+            database::clearInteractionFromConversation(pimpl_->db, convId, interactionId);
+            conversation.interactions.erase(interactionId);
+        } catch (const std::out_of_range& e) {
+            qDebug() << "can't find interaction from conversation: " << e.what();
+            return;
+        }
+    }
+    emit interactionRemoved(convId, interactionId);
+
+    // Send a new interaction like the previous one
+    if (interactionType == interaction::Type::TEXT) {
+        sendMessage(convId, body);
+    } else {
+        // send file
+        QFileInfo f(body.c_str());
+        sendFile(convId, body, f.fileName().toStdString());
+    }
+}
+
 void
 ConversationModel::clearAllHistory()
 {
diff --git a/test/conversationmodeltester.cpp b/test/conversationmodeltester.cpp
index 81216a8640110d8475fc8dbb1bb165ba8ff35df4..996a8a92d4244b59061c435f6e9df0d222082c68 100644
--- a/test/conversationmodeltester.cpp
+++ b/test/conversationmodeltester.cpp
@@ -30,6 +30,7 @@
 #include <api/contactmodel.h>
 #include <api/newcallmodel.h>
 #include <dbus/configurationmanager.h>
+#include <dbus/callmanager.h>
 #include <namedirectory.h>
 
 namespace ring
@@ -393,7 +394,7 @@ ConversationModelTester::testSendMessagesAndClearInteraction()
     CPPUNIT_ASSERT(conversationExists);
 
     accInfo_.conversationModel->clearInteractionFromConversation(firstConversationUid, secondInterId);
-    auto unreadMessage = WaitForSignalHelper(*accInfo_.conversationModel,
+    WaitForSignalHelper(*accInfo_.conversationModel,
         SIGNAL(interactionRemoved(const std::string& convUid, uint64_t interactionId))).wait(1000);
     conversations = accInfo_.conversationModel->allFilteredConversations();
     conversationExists = false;
@@ -463,6 +464,180 @@ ConversationModelTester::testSendMessagesAndClearLastInteraction()
     CPPUNIT_ASSERT(conversationExists);
 }
 
+void
+ConversationModelTester::testRetryToSendTextInteraction()
+{
+    accInfo_.conversationModel->setFilter("");
+    auto conversations = accInfo_.conversationModel->allFilteredConversations();
+    CPPUNIT_ASSERT(conversations.size() != 0);
+    auto firstConversation = accInfo_.conversationModel->filteredConversation(0).uid;
+    accInfo_.conversationModel->sendMessage(firstConversation, "Hello World!");
+    accInfo_.conversationModel->sendMessage(firstConversation, "It's been a long time");
+    accInfo_.conversationModel->sendMessage(firstConversation, "How have you been?");
+    auto conversation = accInfo_.conversationModel->filteredConversation(0);
+    const auto& interactions = conversation.interactions;
+    auto it = interactions.begin();
+    it++;
+    auto secondId = it->first;
+
+    // set failure on one interaction
+    ConfigurationManager::instance().emitAccountMessageStatusChanged(
+                                        "ring0", secondId,
+                                        conversation.participants.front().c_str(),
+                                        static_cast<int>(DRing::Account::MessageStates::FAILURE));
+    // retry sending
+    accInfo_.conversationModel->retryInteraction(conversation.uid, secondId);
+    // no more failure, no more secondId, and second message should be the last
+    conversation = accInfo_.conversationModel->filteredConversation(0);
+    bool hasFailedInteraction = false;
+    bool hasOldSecondInteraction = false;
+    bool secondBodyPresent = false; conversation.interactions.begin()->second.body == "It's been a long time";
+    for (const auto& interaction : conversation.interactions) {
+        if (interaction.second.status == lrc::api::interaction::Status::FAILED)
+            hasFailedInteraction = true;
+        if (interaction.second.body == "It's been a long time")
+            secondBodyPresent = true;
+        if (interaction.first == secondId)
+            hasOldSecondInteraction = true;
+    }
+    CPPUNIT_ASSERT(!hasFailedInteraction);
+    CPPUNIT_ASSERT(!hasOldSecondInteraction);
+    CPPUNIT_ASSERT(secondBodyPresent);
+}
+
+void
+ConversationModelTester::testRetryToSendFileInteraction()
+{
+    accInfo_.conversationModel->setFilter("");
+    auto conversations = accInfo_.conversationModel->allFilteredConversations();
+    CPPUNIT_ASSERT(conversations.size() != 0);
+    auto firstConversation = accInfo_.conversationModel->filteredConversation(0).uid;
+    // send file
+
+}
+
+void
+ConversationModelTester::testRetryInvalidInteraction()
+{
+    accInfo_.conversationModel->setFilter("");
+    auto conversations = accInfo_.conversationModel->allFilteredConversations();
+    CPPUNIT_ASSERT(conversations.size() != 0);
+    auto firstConversation = accInfo_.conversationModel->filteredConversation(0).uid;
+    accInfo_.conversationModel->sendMessage(firstConversation, "Hello World!");
+    accInfo_.conversationModel->sendMessage(firstConversation, "It's been a long time");
+    accInfo_.conversationModel->sendMessage(firstConversation, "How have you been?");
+    auto conversation = accInfo_.conversationModel->filteredConversation(0);
+    const auto& interactions = conversation.interactions;
+    auto it = interactions.begin();
+    it++;
+    auto secondId = it->first;
+
+    // set failure on one interaction
+    ConfigurationManager::instance().emitAccountMessageStatusChanged(
+                                        "ring0", secondId,
+                                        conversation.participants.front().c_str(),
+                                        static_cast<int>(DRing::Account::MessageStates::FAILURE));
+    auto firstConv = accInfo_.conversationModel->filteredConversation(0);
+    // retry sending (should do nothing)
+    accInfo_.conversationModel->retryInteraction(conversation.uid, 1412);
+
+    conversation = accInfo_.conversationModel->filteredConversation(0);
+    auto bIt = firstConv.interactions.begin();
+    auto nIt = conversation.interactions.begin();
+    for (size_t i = 0 ; i < firstConv.interactions.size(); ++i) {
+        CPPUNIT_ASSERT(bIt->second.body == nIt->second.body);
+        CPPUNIT_ASSERT(bIt->second.status == nIt->second.status);
+        CPPUNIT_ASSERT(bIt->second.type == nIt->second.type);
+        bIt++;
+        nIt++;
+    }
+}
+
+void
+ConversationModelTester::testRetryIncomingInteraction()
+{
+    // Add a new message for the first conversation
+    auto conversations = accInfo_.conversationModel->allFilteredConversations();
+    CPPUNIT_ASSERT(conversations.size() != 0);
+    auto firstConversation = accInfo_.conversationModel->filteredConversation(0);
+    QMap<QString, QString> payloads;
+    payloads["text/plain"] = "You're a monster";
+    ConfigurationManager::instance().emitIncomingAccountMessage(accInfo_.id.c_str(),
+        firstConversation.participants.front().c_str(), payloads);
+    auto unreadMessage = WaitForSignalHelper(*accInfo_.conversationModel,
+        SIGNAL(newUnreadMessage(const std::string&, uint64_t, const interaction::Info&))).wait(1000);
+    CPPUNIT_ASSERT_EQUAL(unreadMessage, true);
+
+    // Retry incoming message
+    conversations = accInfo_.conversationModel->allFilteredConversations();
+    CPPUNIT_ASSERT(conversations.size() != 0);
+    firstConversation = accInfo_.conversationModel->filteredConversation(0);
+    auto lastInteraction = *firstConversation.interactions.rbegin();
+    accInfo_.conversationModel->retryInteraction(firstConversation.uid, lastInteraction.first);
+    // Should do nothing
+    firstConversation = accInfo_.conversationModel->filteredConversation(0);
+    auto newLastInteraction = *firstConversation.interactions.rbegin();
+    CPPUNIT_ASSERT(newLastInteraction.second.status == lrc::api::interaction::Status::UNREAD);
+}
+
+void
+ConversationModelTester::testRetryContactInteraction()
+{
+    // Add a new message for the first conversation. The first message will be "contact added"
+    auto conversations = accInfo_.conversationModel->allFilteredConversations();
+    CPPUNIT_ASSERT(conversations.size() != 0);
+    auto firstConversation = accInfo_.conversationModel->filteredConversation(0);
+    QMap<QString, QString> payloads;
+    payloads["text/plain"] = "You're a monster";
+    ConfigurationManager::instance().emitIncomingAccountMessage(accInfo_.id.c_str(),
+        firstConversation.participants.front().c_str(), payloads);
+    auto unreadMessage = WaitForSignalHelper(*accInfo_.conversationModel,
+        SIGNAL(newUnreadMessage(const std::string&, uint64_t, const interaction::Info&))).wait(1000);
+    CPPUNIT_ASSERT_EQUAL(unreadMessage, true);
+
+    // The first message is "Contact added"
+    conversations = accInfo_.conversationModel->allFilteredConversations();
+    CPPUNIT_ASSERT(conversations.size() != 0);
+    firstConversation = accInfo_.conversationModel->filteredConversation(0);
+    auto firstInteraction = *firstConversation.interactions.begin();
+    CPPUNIT_ASSERT(firstInteraction.second.type == lrc::api::interaction::Type::CONTACT);
+
+    // Retry contact
+    accInfo_.conversationModel->retryInteraction(firstConversation.uid, firstInteraction.first);
+    // Should do nothings
+    firstConversation = accInfo_.conversationModel->filteredConversation(0);
+    auto newLastInteraction = *firstConversation.interactions.begin();
+    CPPUNIT_ASSERT(newLastInteraction.second.type == lrc::api::interaction::Type::CONTACT);
+}
+
+void
+ConversationModelTester::testRetryCallInteraction()
+{
+    // Place call
+    auto conversations = accInfo_.conversationModel->allFilteredConversations();
+    CPPUNIT_ASSERT(conversations.size() != 0);
+    auto firstConversation = accInfo_.conversationModel->filteredConversation(0);
+    accInfo_.conversationModel->placeCall(firstConversation.uid);
+    CallManager::instance().emitCallStateChanged(
+        accInfo_.conversationModel->filteredConversation(0).callId.c_str(), "CURRENT", 0);
+    WaitForSignalHelper(*accInfo_.conversationModel, SIGNAL(modelSorted())).wait(1000);
+
+    // Last interaction is a CALL
+    conversations = accInfo_.conversationModel->allFilteredConversations();
+    CPPUNIT_ASSERT(conversations.size() != 0);
+    firstConversation = accInfo_.conversationModel->filteredConversation(0);
+    auto lastInteraction = *firstConversation.interactions.rbegin();
+    CPPUNIT_ASSERT(lastInteraction.second.type == lrc::api::interaction::Type::CALL);
+    // Retry, should do nothing
+    accInfo_.conversationModel->retryInteraction(firstConversation.uid, lastInteraction.first);
+
+    // Should do nothing
+    firstConversation = accInfo_.conversationModel->filteredConversation(0);
+    auto newLastInteraction = *firstConversation.interactions.rbegin();
+    CPPUNIT_ASSERT(newLastInteraction.second.type == lrc::api::interaction::Type::CALL);
+}
+
+
 void
 ConversationModelTester::testReceiveMessageAndSetRead()
 {
diff --git a/test/conversationmodeltester.h b/test/conversationmodeltester.h
index 2bab3ee18a60e21873d0d4818e571dbfe4ad6961..64e787a434063742ecb670bd8b0aaa995eceb9f2 100644
--- a/test/conversationmodeltester.h
+++ b/test/conversationmodeltester.h
@@ -48,6 +48,12 @@ class ConversationModelTester :  public CppUnit::TestFixture {
     CPPUNIT_TEST(testSendMessageAndClearHistory);
     CPPUNIT_TEST(testSendMessagesAndClearInteraction);
     CPPUNIT_TEST(testSendMessagesAndClearLastInteraction);
+    CPPUNIT_TEST(testRetryToSendTextInteraction);
+    CPPUNIT_TEST(testRetryToSendFileInteraction);
+    CPPUNIT_TEST(testRetryInvalidInteraction);
+    CPPUNIT_TEST(testRetryIncomingInteraction);
+    CPPUNIT_TEST(testRetryContactInteraction);
+    CPPUNIT_TEST(testRetryCallInteraction);
     CPPUNIT_TEST(testReceiveMessageAndSetRead);
     CPPUNIT_TEST(testPlaceCall);
     CPPUNIT_TEST(testCreateConference);
@@ -105,6 +111,30 @@ public:
      * lastMessageUid should be updated
      */
     void testSendMessagesAndClearLastInteraction();
+    /**
+     * Send an old failed outgoing text interaction
+     */
+    void testRetryToSendTextInteraction();
+    /**
+     * Send an old failed outgoing file interaction
+     */
+    void testRetryToSendFileInteraction();
+    /**
+     * Retry an unexistant interaction
+     */
+    void testRetryInvalidInteraction();
+    /**
+     * Retry an incoming interaction
+     */
+    void testRetryIncomingInteraction();
+    /**
+     * Retry a contact interaction
+     */
+    void testRetryContactInteraction();
+    /**
+     * Retry a call interaction
+     */
+    void testRetryCallInteraction();
     /**
      * Receives a message from a conversation and set this message READ
      */
diff --git a/test/mocks/callmanager_mock.h b/test/mocks/callmanager_mock.h
index 5b174fc9acb1117111e58f8546a1202da88fe75d..23d56995fcbc986e4e4a36339cd16c911dbca2c7 100644
--- a/test/mocks/callmanager_mock.h
+++ b/test/mocks/callmanager_mock.h
@@ -54,6 +54,10 @@ public:
 
     bool isValid() { return true; }
 
+    void emitCallStateChanged(const QString &callID, const QString &state, int code) {
+        emit callStateChanged(callID, state, code);
+    }
+
 public Q_SLOTS: // METHODS
     bool accept(const QString &callID)
     {
diff --git a/test/mocks/configurationmanager_mock.h b/test/mocks/configurationmanager_mock.h
index 76abe21be97ea2985288d871cdeecede12c5a9d6..90ce44b852beeceb70ed58411e64760e85544631 100644
--- a/test/mocks/configurationmanager_mock.h
+++ b/test/mocks/configurationmanager_mock.h
@@ -108,6 +108,10 @@ public:
        emit incomingAccountMessage(accountId, from, payloads);
    }
 
+   void emitAccountMessageStatusChanged(const QString& accountId, const uint64_t id, const QString& to, int status)
+   {
+       emit accountMessageStatusChanged(accountId, id, to, status);
+   }
 
    std::map<long long, lrc::api::datatransfer::Info> transferInfos_;
    std::map<long long, uint32_t> transferInfosEvent_;