diff --git a/Examples/xx-messenger/Sources/AppCore/AppDependecies.swift b/Examples/xx-messenger/Sources/AppCore/AppDependecies.swift
index c67559af9d580952c14554465d356e27672b0e72..9e55ac6da53b79b6c43352a78f58c78e4020551d 100644
--- a/Examples/xx-messenger/Sources/AppCore/AppDependecies.swift
+++ b/Examples/xx-messenger/Sources/AppCore/AppDependecies.swift
@@ -12,6 +12,7 @@ public struct AppDependencies {
   public var bgQueue: AnySchedulerOf<DispatchQueue>
   public var now: () -> Date
   public var sendMessage: SendMessage
+  public var sendGroupMessage: SendGroupMessage
   public var sendImage: SendImage
   public var messageListener: MessageListenerHandler
   public var receiveFileHandler: ReceiveFileHandler
@@ -46,6 +47,11 @@ extension AppDependencies {
         db: dbManager.getDB,
         now: now
       ),
+      sendGroupMessage: .live(
+        messenger: messenger,
+        db: dbManager.getDB,
+        now: now
+      ),
       sendImage: .live(
         messenger: messenger,
         db: dbManager.getDB,
@@ -85,6 +91,7 @@ extension AppDependencies {
       placeholder: Date(timeIntervalSince1970: 0)
     ),
     sendMessage: .unimplemented,
+    sendGroupMessage: .unimplemented,
     sendImage: .unimplemented,
     messageListener: .unimplemented,
     receiveFileHandler: .unimplemented,
diff --git a/Examples/xx-messenger/Sources/ChatFeature/ChatComponent.swift b/Examples/xx-messenger/Sources/ChatFeature/ChatComponent.swift
index a538e28e2a409f08d7fc994b5716747813d6f493..66585eddbfa3747940dd76e9ff9293103f187587 100644
--- a/Examples/xx-messenger/Sources/ChatFeature/ChatComponent.swift
+++ b/Examples/xx-messenger/Sources/ChatFeature/ChatComponent.swift
@@ -78,6 +78,7 @@ public struct ChatComponent: ReducerProtocol {
   @Dependency(\.app.messenger) var messenger: Messenger
   @Dependency(\.app.dbManager.getDB) var db: DBManagerGetDB
   @Dependency(\.app.sendMessage) var sendMessage: SendMessage
+  @Dependency(\.app.sendGroupMessage) var sendGroupMessage: SendGroupMessage
   @Dependency(\.app.sendImage) var sendImage: SendImage
   @Dependency(\.app.mainQueue) var mainQueue: AnySchedulerOf<DispatchQueue>
   @Dependency(\.app.bgQueue) var bgQueue: AnySchedulerOf<DispatchQueue>
@@ -173,8 +174,16 @@ public struct ChatComponent: ReducerProtocol {
               }
             )
           case .group(let groupId):
-            // TODO: send group message
-            fatalError()
+            sendGroupMessage(
+              text: text,
+              to: groupId,
+              onError: { error in
+                subscriber.send(.sendFailed(error.localizedDescription))
+              },
+              completion: {
+                subscriber.send(completion: .finished)
+              }
+            )
           }
           return AnyCancellable {}
         }
diff --git a/Examples/xx-messenger/Tests/ChatFeatureTests/ChatComponentTests.swift b/Examples/xx-messenger/Tests/ChatFeatureTests/ChatComponentTests.swift
index 4303416c8a1635c917efeb5f99ecde246899f5fc..fb77001cdecd6b590d5760d6421b4cdaa8259b61 100644
--- a/Examples/xx-messenger/Tests/ChatFeatureTests/ChatComponentTests.swift
+++ b/Examples/xx-messenger/Tests/ChatFeatureTests/ChatComponentTests.swift
@@ -306,7 +306,7 @@ final class ChatComponentTests: XCTestCase {
     sendMessageCompletion?()
   }
 
-  func testSendFailure() {
+  func testSendDirectMessageFailure() {
     var sendMessageOnError: SendMessage.OnError?
     var sendMessageCompletion: SendMessage.Completion?
 
@@ -343,6 +343,80 @@ final class ChatComponentTests: XCTestCase {
     }
   }
 
+  func testSendGroupMessage() {
+    let groupId = "group-id".data(using: .utf8)!
+    let text = "Hello"
+    struct SendGroupMessageParams: Equatable {
+      var text: String
+      var groupId: Data
+    }
+    var didSendGroupMessageWithParams: [SendGroupMessageParams] = []
+    var sendGroupMessageCompletion: SendGroupMessage.Completion?
+
+    let store = TestStore(
+      initialState: ChatComponent.State(id: .group(groupId)),
+      reducer: ChatComponent()
+    )
+
+    store.dependencies.app.mainQueue = .immediate
+    store.dependencies.app.bgQueue = .immediate
+    store.dependencies.app.sendGroupMessage.run = { text, groupId, _, completion in
+      didSendGroupMessageWithParams.append(.init(text: text, groupId: groupId))
+      sendGroupMessageCompletion = completion
+    }
+
+    store.send(.set(\.$text, text)) {
+      $0.text = text
+    }
+
+    store.send(.sendTapped) {
+      $0.text = ""
+    }
+
+    XCTAssertNoDifference(didSendGroupMessageWithParams, [
+      .init(text: text, groupId: groupId)
+    ])
+
+    sendGroupMessageCompletion?()
+  }
+
+  func testSendGroupMessageFailure() {
+    var sendGroupMessageOnError: SendGroupMessage.OnError?
+    var sendGroupMessageCompletion: SendGroupMessage.Completion?
+
+    let store = TestStore(
+      initialState: ChatComponent.State(
+        id: .group("group-id".data(using: .utf8)!),
+        text: "Hello"
+      ),
+      reducer: ChatComponent()
+    )
+
+    store.dependencies.app.mainQueue = .immediate
+    store.dependencies.app.bgQueue = .immediate
+    store.dependencies.app.sendGroupMessage.run = { _, _, onError, completion in
+      sendGroupMessageOnError = onError
+      sendGroupMessageCompletion = completion
+    }
+
+    store.send(.sendTapped) {
+      $0.text = ""
+    }
+
+    let error = NSError(domain: "test", code: 123)
+    sendGroupMessageOnError?(error)
+
+    store.receive(.sendFailed(error.localizedDescription)) {
+      $0.sendFailure = error.localizedDescription
+    }
+
+    sendGroupMessageCompletion?()
+
+    store.send(.dismissSendFailureTapped) {
+      $0.sendFailure = nil
+    }
+  }
+
   func testSendImage() {
     struct SendImageParams: Equatable {
       var image: Data