diff --git a/src/api/conversationmodel.h b/src/api/conversationmodel.h
index 8b2857eea8461291b4fcdfc7362c516adc1b9b11..fb3bfe275aa853c2faea20a043b775353ec78b28 100644
--- a/src/api/conversationmodel.h
+++ b/src/api/conversationmodel.h
@@ -78,13 +78,18 @@ public:
      * Get a custom filtered set of conversations
      * @return conversations filtered
      */
-    const ConversationQueue& getFilteredConversations(const profile::Type& filter = profile::Type::INVALID, bool forceUpdate = false) const;
+    const ConversationQueue& getFilteredConversations(const profile::Type& filter = profile::Type::INVALID, bool forceUpdate = false, const bool includeBanned = false) const;
     /**
      * Get the conversation at row in the filtered conversations
      * @param  row
      * @return a copy of the conversation
      */
     conversation::Info filteredConversation(unsigned int row) const;
+    /**
+     * Emit a filterChanged signal to force the client to refresh the filter. For instance
+     * this is required when a contact was banned or un-banned.
+     */
+    void refreshFilter();
     /**
      * Make permanent a temporary contact or a pending request.
      * Ensure that given conversation is stored permanently into the system.
diff --git a/src/contactmodel.cpp b/src/contactmodel.cpp
index 9dd339c7b4e708ce53a54a541a4b23fa56e27319..257c9a1b7c090cb5cf3b5d35b8299a81ad8b7b01 100644
--- a/src/contactmodel.cpp
+++ b/src/contactmodel.cpp
@@ -31,6 +31,7 @@
 #include "api/contact.h"
 #include "api/interaction.h"
 #include "api/newcallmodel.h"
+#include "api/conversationmodel.h"
 #include "callbackshandler.h"
 
 #include "accountmodel.h"
@@ -521,18 +522,37 @@ ContactModelPimpl::slotContactAdded(const std::string& accountId, const std::str
 void
 ContactModelPimpl::slotContactRemoved(const std::string& accountId, const std::string& contactUri, bool banned)
 {
-    Q_UNUSED(banned)
     if (accountId != linked.owner.id)
         return;
+
     {
         std::lock_guard<std::mutex> lk(contactsMtx_);
-        if (contacts.find(contactUri) != contacts.end()) {
+
+        auto contact = contacts.find(contactUri);
+        if (contact == contacts.end()) return;
+
+        if (banned) {
+            contact->second.isBanned = true;
+
+            auto* account = AccountModel::instance().getById(linked.owner.id.c_str());
+            if (not account) {
+                qDebug() << "ContactModel::slotContactsAdded(), nullptr";
+                return;
+            }
+            auto* cm = PhoneDirectoryModel::instance().getNumber(QString(contactUri.c_str()), account);
+            account->bannedContactModel()->add(cm);
+        } else {
             database::removeContact(db, linked.owner.profileInfo.uri, contactUri);
             contacts.erase(contactUri);
-        } else
-            return;
+        }
+    }
+
+    if (banned) {
+        // Update the smartlist
+        linked.owner.conversationModel->refreshFilter();
+    } else {
+        emit linked.contactRemoved(contactUri);
     }
-    emit linked.contactRemoved(contactUri);
 }
 
 void
diff --git a/src/conversationmodel.cpp b/src/conversationmodel.cpp
index 21fc64294cf33e9d2c7713e1cde4cd58b9f25975..92f0502953bce37c11195f2244a7b51431d6fb8f 100644
--- a/src/conversationmodel.cpp
+++ b/src/conversationmodel.cpp
@@ -281,7 +281,17 @@ ConversationModel::allFilteredConversations() const
         pimpl_->filteredConversations.begin(),
         [this] (const conversation::Info& entry) {
             auto contactInfo = owner.contactModel->getContact(entry.participants.front());
-            // Check type
+
+            /* Check contact */
+            // If contact is banned, only match if filter is a perfect match
+            if (contactInfo.isBanned) {
+                if (pimpl_->filter == "") return false;
+                return contactInfo.profileInfo.uri == pimpl_->filter
+                       || contactInfo.profileInfo.alias == pimpl_->filter
+                       || contactInfo.registeredName == pimpl_->filter;
+            }
+
+            /* Check type */
             if (pimpl_->typeFilter != profile::Type::PENDING) {
                 // Remove pending contacts and get the temporary item if filter is not empty
                 if (contactInfo.profileInfo.type == profile::Type::PENDING)
@@ -294,7 +304,7 @@ ConversationModel::allFilteredConversations() const
                     return false;
             }
 
-            // Check contact
+            // Otherwise perform usual regex search
             try {
                 auto regexFilter = std::regex(pimpl_->filter, std::regex_constants::icase);
                 bool result = std::regex_search(contactInfo.profileInfo.uri, regexFilter)
@@ -315,7 +325,7 @@ ConversationModel::allFilteredConversations() const
 }
 
 const ConversationModel::ConversationQueue&
-ConversationModel::getFilteredConversations(const profile::Type& filter, bool forceUpdate) const
+ConversationModel::getFilteredConversations(const profile::Type& filter, bool forceUpdate, const bool includeBanned) const
 {
     if (pimpl_->customTypeFilter == filter && !pimpl_->dirtyConversations.second && !forceUpdate)
         return pimpl_->customFilteredConversations;
@@ -326,8 +336,9 @@ ConversationModel::getFilteredConversations(const profile::Type& filter, bool fo
     auto it = std::copy_if(
         pimpl_->conversations.begin(), pimpl_->conversations.end(),
         pimpl_->customFilteredConversations.begin(),
-        [this] (const conversation::Info& entry) {
+        [this, &includeBanned] (const conversation::Info& entry) {
             auto contactInfo = owner.contactModel->getContact(entry.participants.front());
+            if (!includeBanned && contactInfo.isBanned) return false;
             return (contactInfo.profileInfo.type == pimpl_->customTypeFilter);
         });
     pimpl_->customFilteredConversations.resize(std::distance(pimpl_->customFilteredConversations.begin(), it));
@@ -625,6 +636,13 @@ ConversationModel::sendMessage(const std::string& uid, const std::string& body)
     emit modelSorted();
 }
 
+void
+ConversationModel::refreshFilter()
+{
+    pimpl_->dirtyConversations = {true, true};
+    emit filterChanged();
+}
+
 void
 ConversationModel::setFilter(const std::string& filter)
 {